From 04e5975a5a9cf2a03e614aa9d6352fc02c258305 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 26 Apr 2018 17:52:03 +0900 Subject: [PATCH 001/130] Fix testRegisterUsageCallback failure in setUp LocalServices.addService in NetworkStatsService is currently failing with IllegalStateException "Overriding service registration". Setting up LocalServices in the test to avoid this issue might be possible, but moving the registration to the only non-test caller of that constructor as done here solves the issue and avoids side-effects from a constructor. Test: this test passes in master through runtest frameworks-net Bug: b/78487385 Bug: b/80082746 Change-Id: I884a7a8bd7db3fcd220b785ba9914ac8c77720f0 --- .../java/com/android/server/net/NetworkStatsServiceTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 280e4c234e..f89f303a13 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -227,9 +227,6 @@ public class NetworkStatsServiceTest { @After public void tearDown() throws Exception { - // Registered by NetworkStatsService's constructor. - LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class); - IoUtils.deleteContents(mStatsDir); mServiceContext = null; From 585747963140fdc8e0fb86ffbd942702a7f44a80 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Wed, 8 Aug 2018 14:44:44 +0100 Subject: [PATCH 002/130] Add @UnsupportedAppUsage annotations For packages: android.net.wimax android.net.wifi.p2p.nsd android.net.wifi.p2p android.net.wifi.hotspot2.pps android.net.wifi.hotspot2.omadm android.net.wifi.hotspot2 android.net.wifi.aware android.net.wifi android.net.util android.net.sip android.net.rtp android.net.nsd android.net.metrics android.net.lowpan android.net.http android.net.captiveportal android.net This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Change-Id: I520be7a4c79e68310c12e4f55bf66acaa94145a1 --- .../java/android/net/ConnectivityManager.java | 52 +++++++++++++++++++ core/java/android/net/IpConfiguration.java | 5 ++ core/java/android/net/LinkAddress.java | 8 +++ core/java/android/net/LinkProperties.java | 46 ++++++++++++++++ core/java/android/net/MacAddress.java | 2 + core/java/android/net/Network.java | 3 ++ core/java/android/net/NetworkAgent.java | 2 + .../java/android/net/NetworkCapabilities.java | 12 +++++ core/java/android/net/NetworkInfo.java | 8 +++ core/java/android/net/NetworkRequest.java | 6 +++ core/java/android/net/NetworkState.java | 4 ++ core/java/android/net/NetworkUtils.java | 11 ++++ core/java/android/net/ProxyInfo.java | 2 + core/java/android/net/RouteInfo.java | 10 ++++ .../android/net/StaticIpConfiguration.java | 7 +++ 15 files changed, 178 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 104134ab85..fb916d38f3 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -22,6 +22,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -311,6 +312,7 @@ public class ConnectivityManager { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @UnsupportedAppUsage public static final String INET_CONDITION_ACTION = "android.net.conn.INET_CONDITION_ACTION"; @@ -325,6 +327,7 @@ public class ConnectivityManager { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @UnsupportedAppUsage public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"; @@ -333,6 +336,7 @@ public class ConnectivityManager { * gives a String[] listing all the interfaces configured for * tethering and currently available for tethering. */ + @UnsupportedAppUsage public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; /** @@ -347,6 +351,7 @@ public class ConnectivityManager { * gives a String[] listing all the interfaces currently tethered * (ie, has DHCPv4 support and packets potentially forwarded/NATed) */ + @UnsupportedAppUsage public static final String EXTRA_ACTIVE_TETHER = "tetherArray"; /** @@ -355,6 +360,7 @@ public class ConnectivityManager { * failed. Use {@link #getLastTetherError} to find the error code * for any interfaces listed here. */ + @UnsupportedAppUsage public static final String EXTRA_ERRORED_TETHER = "erroredArray"; /** @@ -459,6 +465,7 @@ public class ConnectivityManager { * The absence of a connection type. * @hide */ + @UnsupportedAppUsage public static final int TYPE_NONE = -1; /** @@ -575,6 +582,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated + @UnsupportedAppUsage public static final int TYPE_MOBILE_FOTA = 10; /** @@ -583,6 +591,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated + @UnsupportedAppUsage public static final int TYPE_MOBILE_IMS = 11; /** @@ -591,6 +600,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated + @UnsupportedAppUsage public static final int TYPE_MOBILE_CBS = 12; /** @@ -600,6 +610,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated + @UnsupportedAppUsage public static final int TYPE_WIFI_P2P = 13; /** @@ -608,6 +619,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated + @UnsupportedAppUsage public static final int TYPE_MOBILE_IA = 14; /** @@ -617,6 +629,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated + @UnsupportedAppUsage public static final int TYPE_MOBILE_EMERGENCY = 15; /** @@ -625,6 +638,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated + @UnsupportedAppUsage public static final int TYPE_PROXY = 16; /** @@ -707,6 +721,7 @@ public class ConnectivityManager { */ public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC; + @UnsupportedAppUsage private final IConnectivityManager mService; /** * A kludge to facilitate static access where a Context pointer isn't available, like in the @@ -743,6 +758,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated + @UnsupportedAppUsage public static String getNetworkTypeName(int type) { switch (type) { case TYPE_NONE: @@ -797,6 +813,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated + @UnsupportedAppUsage public static boolean isNetworkTypeMobile(int networkType) { switch (networkType) { case TYPE_MOBILE: @@ -1010,6 +1027,7 @@ public class ConnectivityManager { * {@hide} */ @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) + @UnsupportedAppUsage public NetworkInfo getActiveNetworkInfoForUid(int uid) { return getActiveNetworkInfoForUid(uid, false); } @@ -1107,6 +1125,7 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public Network getNetworkForType(int networkType) { try { return mService.getNetworkForType(networkType); @@ -1135,6 +1154,7 @@ public class ConnectivityManager { * the Networks that applications run by the given user will use by default. * @hide */ + @UnsupportedAppUsage public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) { try { return mService.getDefaultNetworkCapabilitiesForUser(userId); @@ -1153,6 +1173,7 @@ public class ConnectivityManager { * {@hide} */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public LinkProperties getActiveLinkProperties() { try { return mService.getActiveLinkProperties(); @@ -1177,6 +1198,7 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public LinkProperties getLinkProperties(int networkType) { try { return mService.getLinkPropertiesForType(networkType); @@ -1332,6 +1354,7 @@ public class ConnectivityManager { return 1; } + @UnsupportedAppUsage private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) { if (networkType == TYPE_MOBILE) { switch (feature) { @@ -1495,6 +1518,7 @@ public class ConnectivityManager { }; } + @UnsupportedAppUsage private static final HashMap sLegacyRequests = new HashMap<>(); @@ -1523,6 +1547,7 @@ public class ConnectivityManager { Log.d(TAG, "expireRequest with " + ourSeqNum + ", " + sequenceNum); } + @UnsupportedAppUsage private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) { int delay = -1; int type = legacyTypeForNetworkCapabilities(netCap); @@ -1552,6 +1577,7 @@ public class ConnectivityManager { } } + @UnsupportedAppUsage private boolean removeRequestForFeature(NetworkCapabilities netCap) { final LegacyRequest l; synchronized (sLegacyRequests) { @@ -1619,10 +1645,13 @@ public class ConnectivityManager { /** @hide */ public static class PacketKeepaliveCallback { /** The requested keepalive was successfully started. */ + @UnsupportedAppUsage public void onStarted() {} /** The keepalive was successfully stopped. */ + @UnsupportedAppUsage public void onStopped() {} /** An error occurred. */ + @UnsupportedAppUsage public void onError(int error) {} } @@ -1689,6 +1718,7 @@ public class ConnectivityManager { mLooper.quit(); } + @UnsupportedAppUsage public void stop() { try { mService.stopKeepalive(mNetwork, mSlot); @@ -1744,6 +1774,7 @@ public class ConnectivityManager { * * @hide */ + @UnsupportedAppUsage public PacketKeepalive startNattKeepalive( Network network, int intervalSeconds, PacketKeepaliveCallback callback, InetAddress srcAddr, int srcPort, InetAddress dstAddr) { @@ -1805,6 +1836,7 @@ public class ConnectivityManager { * {@link #bindProcessToNetwork} API. */ @Deprecated + @UnsupportedAppUsage public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { checkLegacyRoutingApiAccess(); try { @@ -1848,12 +1880,14 @@ public class ConnectivityManager { * @hide */ @Deprecated + @UnsupportedAppUsage public void setBackgroundDataSetting(boolean allowBackgroundData) { // ignored } /** {@hide} */ @Deprecated + @UnsupportedAppUsage public NetworkQuotaInfo getActiveNetworkQuotaInfo() { try { return mService.getActiveNetworkQuotaInfo(); @@ -1867,6 +1901,7 @@ public class ConnectivityManager { * @deprecated Talk to TelephonyManager directly */ @Deprecated + @UnsupportedAppUsage public boolean getMobileDataEnabled() { IBinder b = ServiceManager.getService(Context.TELEPHONY_SERVICE); if (b != null) { @@ -1986,6 +2021,7 @@ public class ConnectivityManager { } /** {@hide} */ + @UnsupportedAppUsage public static ConnectivityManager from(Context context) { return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); } @@ -2036,6 +2072,7 @@ public class ConnectivityManager { * @hide */ @Deprecated + @UnsupportedAppUsage private static ConnectivityManager getInstance() { if (getInstanceOrNull() == null) { throw new IllegalStateException("No ConnectivityManager yet constructed"); @@ -2052,6 +2089,7 @@ public class ConnectivityManager { * {@hide} */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public String[] getTetherableIfaces() { try { return mService.getTetherableIfaces(); @@ -2068,6 +2106,7 @@ public class ConnectivityManager { * {@hide} */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public String[] getTetheredIfaces() { try { return mService.getTetheredIfaces(); @@ -2090,6 +2129,7 @@ public class ConnectivityManager { * {@hide} */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public String[] getTetheringErroredIfaces() { try { return mService.getTetheringErroredIfaces(); @@ -2136,6 +2176,7 @@ public class ConnectivityManager { * * {@hide} */ + @UnsupportedAppUsage public int tether(String iface) { try { String pkgName = mContext.getOpPackageName(); @@ -2164,6 +2205,7 @@ public class ConnectivityManager { * * {@hide} */ + @UnsupportedAppUsage public int untether(String iface) { try { String pkgName = mContext.getOpPackageName(); @@ -2317,6 +2359,7 @@ public class ConnectivityManager { * {@hide} */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public String[] getTetherableUsbRegexs() { try { return mService.getTetherableUsbRegexs(); @@ -2336,6 +2379,7 @@ public class ConnectivityManager { * {@hide} */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public String[] getTetherableWifiRegexs() { try { return mService.getTetherableWifiRegexs(); @@ -2355,6 +2399,7 @@ public class ConnectivityManager { * {@hide} */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public String[] getTetherableBluetoothRegexs() { try { return mService.getTetherableBluetoothRegexs(); @@ -2380,6 +2425,7 @@ public class ConnectivityManager { * * {@hide} */ + @UnsupportedAppUsage public int setUsbTethering(boolean enable) { try { String pkgName = mContext.getOpPackageName(); @@ -2426,6 +2472,7 @@ public class ConnectivityManager { * {@hide} */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public int getLastTetherError(String iface) { try { return mService.getLastTetherError(iface); @@ -2579,6 +2626,7 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @UnsupportedAppUsage public boolean isNetworkSupported(int networkType) { try { return mService.isNetworkSupported(networkType); @@ -2680,6 +2728,7 @@ public class ConnectivityManager { * @hide */ @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) + @UnsupportedAppUsage public void setAirplaneMode(boolean enable) { try { mService.setAirplaneMode(enable); @@ -2689,6 +2738,7 @@ public class ConnectivityManager { } /** {@hide} */ + @UnsupportedAppUsage public void registerNetworkFactory(Messenger messenger, String name) { try { mService.registerNetworkFactory(messenger, name); @@ -2698,6 +2748,7 @@ public class ConnectivityManager { } /** {@hide} */ + @UnsupportedAppUsage public void unregisterNetworkFactory(Messenger messenger) { try { mService.unregisterNetworkFactory(messenger); @@ -3786,6 +3837,7 @@ public class ConnectivityManager { * @deprecated This is strictly for legacy usage to support {@link #startUsingNetworkFeature}. */ @Deprecated + @UnsupportedAppUsage public static boolean setProcessDefaultNetworkForHostResolution(Network network) { return NetworkUtils.bindProcessToNetworkForHostResolution( network == null ? NETID_UNSET : network.netId); diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java index fe69f2966d..7543920e36 100644 --- a/core/java/android/net/IpConfiguration.java +++ b/core/java/android/net/IpConfiguration.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.net.StaticIpConfiguration; import android.os.Parcel; import android.os.Parcelable; @@ -32,6 +33,7 @@ public class IpConfiguration implements Parcelable { public enum IpAssignment { /* Use statically configured IP settings. Configuration can be accessed * with staticIpConfiguration */ + @UnsupportedAppUsage STATIC, /* Use dynamically configured IP settigns */ DHCP, @@ -47,6 +49,7 @@ public class IpConfiguration implements Parcelable { public enum ProxySettings { /* No proxy is to be used. Any existing proxy settings * should be cleared. */ + @UnsupportedAppUsage NONE, /* Use statically configured proxy. Configuration can be accessed * with httpProxy. */ @@ -61,6 +64,7 @@ public class IpConfiguration implements Parcelable { public ProxySettings proxySettings; + @UnsupportedAppUsage public ProxyInfo httpProxy; private void init(IpAssignment ipAssignment, @@ -79,6 +83,7 @@ public class IpConfiguration implements Parcelable { init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null); } + @UnsupportedAppUsage public IpConfiguration(IpAssignment ipAssignment, ProxySettings proxySettings, StaticIpConfiguration staticIpConfiguration, diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index bcfe938823..1bc0d327ab 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -25,6 +25,7 @@ import static android.system.OsConstants.RT_SCOPE_LINK; import static android.system.OsConstants.RT_SCOPE_SITE; import static android.system.OsConstants.RT_SCOPE_UNIVERSE; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.Pair; @@ -54,11 +55,13 @@ public class LinkAddress implements Parcelable { /** * IPv4 or IPv6 address. */ + @UnsupportedAppUsage private InetAddress address; /** * Prefix length. */ + @UnsupportedAppUsage private int prefixLength; /** @@ -112,6 +115,7 @@ public class LinkAddress implements Parcelable { * @return true if the address is IPv6. * @hide */ + @UnsupportedAppUsage public boolean isIPv6() { return address instanceof Inet6Address; } @@ -163,6 +167,7 @@ public class LinkAddress implements Parcelable { * @param prefixLength The prefix length. * @hide */ + @UnsupportedAppUsage public LinkAddress(InetAddress address, int prefixLength) { this(address, prefixLength, 0, 0); this.scope = scopeForUnicastAddress(address); @@ -185,6 +190,7 @@ public class LinkAddress implements Parcelable { * @param string The string to parse. * @hide */ + @UnsupportedAppUsage public LinkAddress(String address) { this(address, 0, 0); this.scope = scopeForUnicastAddress(this.address); @@ -255,6 +261,7 @@ public class LinkAddress implements Parcelable { * otherwise. * @hide */ + @UnsupportedAppUsage public boolean isSameAddressAs(LinkAddress other) { return address.equals(other.address) && prefixLength == other.prefixLength; } @@ -278,6 +285,7 @@ public class LinkAddress implements Parcelable { * TODO: Delete all callers and remove in favour of getPrefixLength(). * @hide */ + @UnsupportedAppUsage public int getNetworkPrefixLength() { return getPrefixLength(); } diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index bd2db92b78..1b9a66cd6e 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -18,6 +18,7 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -48,6 +49,7 @@ import java.util.StringJoiner; */ public final class LinkProperties implements Parcelable { // The interface described by the network link. + @UnsupportedAppUsage private String mIfaceName; private ArrayList mLinkAddresses = new ArrayList<>(); private ArrayList mDnses = new ArrayList<>(); @@ -103,9 +105,13 @@ public final class LinkProperties implements Parcelable { * @hide */ public enum ProvisioningChange { + @UnsupportedAppUsage STILL_NOT_PROVISIONED, + @UnsupportedAppUsage LOST_PROVISIONING, + @UnsupportedAppUsage GAINED_PROVISIONING, + @UnsupportedAppUsage STILL_PROVISIONED, } @@ -114,6 +120,7 @@ public final class LinkProperties implements Parcelable { * * @hide */ + @UnsupportedAppUsage public static ProvisioningChange compareProvisioning( LinkProperties before, LinkProperties after) { if (before.isProvisioned() && after.isProvisioned()) { @@ -154,12 +161,14 @@ public final class LinkProperties implements Parcelable { /** * @hide */ + @UnsupportedAppUsage public LinkProperties() { } /** * @hide */ + @UnsupportedAppUsage public LinkProperties(LinkProperties source) { if (source != null) { mIfaceName = source.mIfaceName; @@ -186,6 +195,7 @@ public final class LinkProperties implements Parcelable { * @param iface The name of the network interface used for this link. * @hide */ + @UnsupportedAppUsage public void setInterfaceName(String iface) { mIfaceName = iface; ArrayList newRoutes = new ArrayList<>(mRoutes.size()); @@ -207,6 +217,7 @@ public final class LinkProperties implements Parcelable { /** * @hide */ + @UnsupportedAppUsage public List getAllInterfaceNames() { List interfaceNames = new ArrayList<>(mStackedLinks.size() + 1); if (mIfaceName != null) interfaceNames.add(mIfaceName); @@ -226,6 +237,7 @@ public final class LinkProperties implements Parcelable { * @return An unmodifiable {@link List} of {@link InetAddress} for this link. * @hide */ + @UnsupportedAppUsage public List getAddresses() { List addresses = new ArrayList<>(); for (LinkAddress linkAddress : mLinkAddresses) { @@ -238,6 +250,7 @@ public final class LinkProperties implements Parcelable { * Returns all the addresses on this link and all the links stacked above it. * @hide */ + @UnsupportedAppUsage public List getAllAddresses() { List addresses = new ArrayList<>(); for (LinkAddress linkAddress : mLinkAddresses) { @@ -265,6 +278,7 @@ public final class LinkProperties implements Parcelable { * @return true if {@code address} was added or updated, false otherwise. * @hide */ + @UnsupportedAppUsage public boolean addLinkAddress(LinkAddress address) { if (address == null) { return false; @@ -315,6 +329,7 @@ public final class LinkProperties implements Parcelable { * Returns all the addresses on this link and all the links stacked above it. * @hide */ + @UnsupportedAppUsage public List getAllLinkAddresses() { List addresses = new ArrayList<>(mLinkAddresses); for (LinkProperties stacked: mStackedLinks.values()) { @@ -331,6 +346,7 @@ public final class LinkProperties implements Parcelable { * object. * @hide */ + @UnsupportedAppUsage public void setLinkAddresses(Collection addresses) { mLinkAddresses.clear(); for (LinkAddress address: addresses) { @@ -345,6 +361,7 @@ public final class LinkProperties implements Parcelable { * @return true if the DNS server was added, false if it was already present. * @hide */ + @UnsupportedAppUsage public boolean addDnsServer(InetAddress dnsServer) { if (dnsServer != null && !mDnses.contains(dnsServer)) { mDnses.add(dnsServer); @@ -360,6 +377,7 @@ public final class LinkProperties implements Parcelable { * @return true if the DNS server was removed, false if it did not exist. * @hide */ + @UnsupportedAppUsage public boolean removeDnsServer(InetAddress dnsServer) { if (dnsServer != null) { return mDnses.remove(dnsServer); @@ -374,6 +392,7 @@ public final class LinkProperties implements Parcelable { * @param dnsServers The {@link Collection} of DNS servers to set in this object. * @hide */ + @UnsupportedAppUsage public void setDnsServers(Collection dnsServers) { mDnses.clear(); for (InetAddress dnsServer: dnsServers) { @@ -510,6 +529,7 @@ public final class LinkProperties implements Parcelable { * domains to search when resolving host names on this link. * @hide */ + @UnsupportedAppUsage public void setDomains(String domains) { mDomains = domains; } @@ -532,6 +552,7 @@ public final class LinkProperties implements Parcelable { * @param mtu The MTU to use for this link. * @hide */ + @UnsupportedAppUsage public void setMtu(int mtu) { mMtu = mtu; } @@ -543,6 +564,7 @@ public final class LinkProperties implements Parcelable { * @return The mtu value set for this link. * @hide */ + @UnsupportedAppUsage public int getMtu() { return mMtu; } @@ -555,6 +577,7 @@ public final class LinkProperties implements Parcelable { * * @hide */ + @UnsupportedAppUsage public void setTcpBufferSizes(String tcpBufferSizes) { mTcpBufferSizes = tcpBufferSizes; } @@ -566,6 +589,7 @@ public final class LinkProperties implements Parcelable { * * @hide */ + @UnsupportedAppUsage public String getTcpBufferSizes() { return mTcpBufferSizes; } @@ -589,6 +613,7 @@ public final class LinkProperties implements Parcelable { * * @hide */ + @UnsupportedAppUsage public boolean addRoute(RouteInfo route) { if (route != null) { String routeIface = route.getInterface(); @@ -615,6 +640,7 @@ public final class LinkProperties implements Parcelable { * * @hide */ + @UnsupportedAppUsage public boolean removeRoute(RouteInfo route) { return route != null && Objects.equals(mIfaceName, route.getInterface()) && @@ -645,6 +671,7 @@ public final class LinkProperties implements Parcelable { * Returns all the routes on this link and all the links stacked above it. * @hide */ + @UnsupportedAppUsage public List getAllRoutes() { List routes = new ArrayList<>(mRoutes); for (LinkProperties stacked: mStackedLinks.values()) { @@ -661,6 +688,7 @@ public final class LinkProperties implements Parcelable { * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link. * @hide */ + @UnsupportedAppUsage public void setHttpProxy(ProxyInfo proxy) { mHttpProxy = proxy; } @@ -685,6 +713,7 @@ public final class LinkProperties implements Parcelable { * @return true if the link was stacked, false otherwise. * @hide */ + @UnsupportedAppUsage public boolean addStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { mStackedLinks.put(link.getInterfaceName(), link); @@ -715,6 +744,7 @@ public final class LinkProperties implements Parcelable { * Returns all the links stacked on top of this link. * @hide */ + @UnsupportedAppUsage public @NonNull List getStackedLinks() { if (mStackedLinks.isEmpty()) { return Collections.emptyList(); @@ -730,6 +760,7 @@ public final class LinkProperties implements Parcelable { * Clears this object to its initial state. * @hide */ + @UnsupportedAppUsage public void clear() { mIfaceName = null; mLinkAddresses.clear(); @@ -831,6 +862,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if there is an IPv4 address, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean hasIPv4Address() { for (LinkAddress address : mLinkAddresses) { if (address.getAddress() instanceof Inet4Address) { @@ -858,6 +890,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean hasGlobalIPv6Address() { for (LinkAddress address : mLinkAddresses) { if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) { @@ -873,6 +906,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if there is an IPv4 default route, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean hasIPv4DefaultRoute() { for (RouteInfo r : mRoutes) { if (r.isIPv4Default()) { @@ -888,6 +922,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if there is an IPv6 default route, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean hasIPv6DefaultRoute() { for (RouteInfo r : mRoutes) { if (r.isIPv6Default()) { @@ -903,6 +938,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean hasIPv4DnsServer() { for (InetAddress ia : mDnses) { if (ia instanceof Inet4Address) { @@ -918,6 +954,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean hasIPv6DnsServer() { for (InetAddress ia : mDnses) { if (ia instanceof Inet6Address) { @@ -947,6 +984,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if the link is provisioned, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean isIPv6Provisioned() { return (hasGlobalIPv6Address() && hasIPv6DefaultRoute() && @@ -960,6 +998,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if the link is provisioned, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean isProvisioned() { return (isIPv4Provisioned() || isIPv6Provisioned()); } @@ -971,6 +1010,7 @@ public final class LinkProperties implements Parcelable { * {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean isReachable(InetAddress ip) { final List allRoutes = getAllRoutes(); // If we don't have a route to this IP address, it's not reachable. @@ -1008,6 +1048,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if both are identical, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean isIdenticalInterfaceName(LinkProperties target) { return TextUtils.equals(getInterfaceName(), target.getInterfaceName()); } @@ -1019,6 +1060,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if both are identical, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean isIdenticalAddresses(LinkProperties target) { Collection targetAddresses = target.getAddresses(); Collection sourceAddresses = getAddresses(); @@ -1033,6 +1075,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if both are identical, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean isIdenticalDnses(LinkProperties target) { Collection targetDnses = target.getDnsServers(); String targetDomains = target.getDomains(); @@ -1080,6 +1123,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if both are identical, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean isIdenticalRoutes(LinkProperties target) { Collection targetRoutes = target.getRoutes(); return (mRoutes.size() == targetRoutes.size()) ? @@ -1093,6 +1137,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if both are identical, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean isIdenticalHttpProxy(LinkProperties target) { return getHttpProxy() == null ? target.getHttpProxy() == null : getHttpProxy().equals(target.getHttpProxy()); @@ -1105,6 +1150,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if both are identical, {@code false} otherwise. * @hide */ + @UnsupportedAppUsage public boolean isIdenticalStackedLinks(LinkProperties target) { if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) { return false; diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 74d64704c8..98f356722b 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -18,6 +18,7 @@ package android.net; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -50,6 +51,7 @@ public final class MacAddress implements Parcelable { * The MacAddress zero MAC address. * @hide */ + @UnsupportedAppUsage public static final MacAddress ALL_ZEROS_ADDRESS = new MacAddress(0); /** @hide */ diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 512e35e707..142023d40c 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.system.ErrnoException; @@ -59,6 +60,7 @@ public class Network implements Parcelable { /** * @hide */ + @UnsupportedAppUsage public final int netId; // Objects used to perform per-network operations such as getSocketFactory @@ -103,6 +105,7 @@ public class Network implements Parcelable { /** * @hide */ + @UnsupportedAppUsage public Network(int netId) { this.netId = netId; } diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index e6b3fa8177..114b423c31 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.ConnectivityManager.PacketKeepalive; import android.os.Bundle; @@ -351,6 +352,7 @@ public abstract class NetworkAgent extends Handler { /** * Called by the bearer code when it has new NetworkInfo data. */ + @UnsupportedAppUsage public void sendNetworkInfo(NetworkInfo networkInfo) { queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); } diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 72b4bfd57d..fd1e5f2338 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -19,6 +19,7 @@ package android.net; import android.annotation.IntDef; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.annotation.UnsupportedAppUsage; import android.net.ConnectivityManager.NetworkCallback; import android.os.Parcel; import android.os.Parcelable; @@ -56,6 +57,7 @@ public final class NetworkCapabilities implements Parcelable { /** * @hide */ + @UnsupportedAppUsage public NetworkCapabilities() { clearAll(); mNetworkCapabilities = DEFAULT_CAPABILITIES; @@ -103,6 +105,7 @@ public final class NetworkCapabilities implements Parcelable { * Represents the network's capabilities. If any are specified they will be satisfied * by any Network that matches all of them. */ + @UnsupportedAppUsage private long mNetworkCapabilities; /** @@ -371,6 +374,7 @@ public final class NetworkCapabilities implements Parcelable { * @return This NetworkCapabilities instance, to facilitate chaining. * @hide */ + @UnsupportedAppUsage public NetworkCapabilities addCapability(@NetCapability int capability) { checkValidCapability(capability); mNetworkCapabilities |= 1 << capability; @@ -407,6 +411,7 @@ public final class NetworkCapabilities implements Parcelable { * @return This NetworkCapabilities instance, to facilitate chaining. * @hide */ + @UnsupportedAppUsage public NetworkCapabilities removeCapability(@NetCapability int capability) { checkValidCapability(capability); final long mask = ~(1 << capability); @@ -659,6 +664,7 @@ public final class NetworkCapabilities implements Parcelable { * @return This NetworkCapabilities instance, to facilitate chaining. * @hide */ + @UnsupportedAppUsage public NetworkCapabilities addTransportType(@Transport int transportType) { checkValidTransportType(transportType); mTransportTypes |= 1 << transportType; @@ -898,6 +904,7 @@ public final class NetworkCapabilities implements Parcelable { * specifier. See {@link #setNetworkSpecifier}. * @hide */ + @UnsupportedAppUsage public NetworkSpecifier getNetworkSpecifier() { return mNetworkSpecifier; } @@ -930,6 +937,7 @@ public final class NetworkCapabilities implements Parcelable { * Signal strength. This is a signed integer, and higher values indicate better signal. * The exact units are bearer-dependent. For example, Wi-Fi uses RSSI. */ + @UnsupportedAppUsage private int mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; /** @@ -945,6 +953,7 @@ public final class NetworkCapabilities implements Parcelable { * @param signalStrength the bearer-specific signal strength. * @hide */ + @UnsupportedAppUsage public NetworkCapabilities setSignalStrength(int signalStrength) { mSignalStrength = signalStrength; return this; @@ -955,6 +964,7 @@ public final class NetworkCapabilities implements Parcelable { * * @hide */ + @UnsupportedAppUsage public boolean hasSignalStrength() { return mSignalStrength > SIGNAL_STRENGTH_UNSPECIFIED; } @@ -965,6 +975,7 @@ public final class NetworkCapabilities implements Parcelable { * @return The bearer-specific signal strength. * @hide */ + @UnsupportedAppUsage public int getSignalStrength() { return mSignalStrength; } @@ -1544,6 +1555,7 @@ public final class NetworkCapabilities implements Parcelable { /** * @hide */ + @UnsupportedAppUsage public static String transportNamesOf(@Transport int[] types) { StringJoiner joiner = new StringJoiner("|"); if (types != null) { diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 999771a18e..d912dd105f 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -129,6 +130,7 @@ public class NetworkInfo implements Parcelable { /** * @hide */ + @UnsupportedAppUsage public NetworkInfo(int type, int subtype, String typeName, String subtypeName) { if (!ConnectivityManager.isNetworkTypeValid(type) && type != ConnectivityManager.TYPE_NONE) { @@ -143,6 +145,7 @@ public class NetworkInfo implements Parcelable { } /** {@hide} */ + @UnsupportedAppUsage public NetworkInfo(NetworkInfo source) { if (source != null) { synchronized (source) { @@ -209,6 +212,7 @@ public class NetworkInfo implements Parcelable { /** * @hide */ + @UnsupportedAppUsage public void setSubtype(int subtype, String subtypeName) { synchronized (this) { mSubtype = subtype; @@ -317,6 +321,7 @@ public class NetworkInfo implements Parcelable { * @hide */ @Deprecated + @UnsupportedAppUsage public void setIsAvailable(boolean isAvailable) { synchronized (this) { mIsAvailable = isAvailable; @@ -347,6 +352,7 @@ public class NetworkInfo implements Parcelable { * @hide */ @Deprecated + @UnsupportedAppUsage public void setFailover(boolean isFailover) { synchronized (this) { mIsFailover = isFailover; @@ -377,6 +383,7 @@ public class NetworkInfo implements Parcelable { */ @VisibleForTesting @Deprecated + @UnsupportedAppUsage public void setRoaming(boolean isRoaming) { synchronized (this) { mIsRoaming = isRoaming; @@ -422,6 +429,7 @@ public class NetworkInfo implements Parcelable { * @hide */ @Deprecated + @UnsupportedAppUsage public void setDetailedState(DetailedState detailedState, String reason, String extraInfo) { synchronized (this) { this.mDetailedState = detailedState; diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 16c2342a89..04b6b44013 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.UnsupportedAppUsage; import android.net.NetworkCapabilities.NetCapability; import android.net.NetworkCapabilities.Transport; import android.os.Parcel; @@ -38,6 +39,7 @@ public class NetworkRequest implements Parcelable { * The {@link NetworkCapabilities} that define this request. * @hide */ + @UnsupportedAppUsage public final @NonNull NetworkCapabilities networkCapabilities; /** @@ -46,6 +48,7 @@ public class NetworkRequest implements Parcelable { * the request. * @hide */ + @UnsupportedAppUsage public final int requestId; /** @@ -53,6 +56,7 @@ public class NetworkRequest implements Parcelable { * Causes CONNECTIVITY_ACTION broadcasts to be sent. * @hide */ + @UnsupportedAppUsage public final int legacyType; /** @@ -241,6 +245,7 @@ public class NetworkRequest implements Parcelable { * @return The builder to facilitate chaining. * @hide */ + @UnsupportedAppUsage public Builder clearCapabilities() { mNetworkCapabilities.clearAll(); return this; @@ -339,6 +344,7 @@ public class NetworkRequest implements Parcelable { * @param signalStrength the bearer-specific signal strength. * @hide */ + @UnsupportedAppUsage public Builder setSignalStrength(int signalStrength) { mNetworkCapabilities.setSignalStrength(signalStrength); return this; diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index 321f9718ee..c545ee205d 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.Slog; @@ -33,6 +34,7 @@ public class NetworkState implements Parcelable { public final NetworkInfo networkInfo; public final LinkProperties linkProperties; public final NetworkCapabilities networkCapabilities; + @UnsupportedAppUsage public final Network network; public final String subscriberId; public final String networkId; @@ -58,6 +60,7 @@ public class NetworkState implements Parcelable { } } + @UnsupportedAppUsage public NetworkState(Parcel in) { networkInfo = in.readParcelable(null); linkProperties = in.readParcelable(null); @@ -82,6 +85,7 @@ public class NetworkState implements Parcelable { out.writeString(networkId); } + @UnsupportedAppUsage public static final Creator CREATOR = new Creator() { @Override public NetworkState createFromParcel(Parcel in) { diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index dc1f8054f6..599ccb287a 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.util.Log; import android.util.Pair; @@ -43,6 +44,7 @@ public class NetworkUtils { /** * Attaches a socket filter that accepts DHCP packets to the given socket. */ + @UnsupportedAppUsage public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException; /** @@ -50,6 +52,7 @@ public class NetworkUtils { * @param fd the socket's {@link FileDescriptor}. * @param packetType the hardware address type, one of ARPHRD_*. */ + @UnsupportedAppUsage public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException; /** @@ -60,6 +63,7 @@ public class NetworkUtils { * @param fd the socket's {@link FileDescriptor}. * @param packetType the hardware address type, one of ARPHRD_*. */ + @UnsupportedAppUsage public native static void attachControlPacketFilter(FileDescriptor fd, int packetType) throws SocketException; @@ -108,6 +112,7 @@ public class NetworkUtils { * this socket will go directly to the underlying network, so its traffic will not be * forwarded through the VPN. */ + @UnsupportedAppUsage public static boolean protectFromVpn(FileDescriptor fd) { return protectFromVpn(fd.getInt$()); } @@ -131,6 +136,7 @@ public class NetworkUtils { * or {@link #intToInet4AddressHTL(int)} */ @Deprecated + @UnsupportedAppUsage public static InetAddress intToInetAddress(int hostAddress) { return intToInet4AddressHTL(hostAddress); } @@ -209,6 +215,7 @@ public class NetworkUtils { * or {@link #prefixLengthToV4NetmaskIntHTL(int)} */ @Deprecated + @UnsupportedAppUsage public static int prefixLengthToNetmaskInt(int prefixLength) throws IllegalArgumentException { return prefixLengthToV4NetmaskIntHTL(prefixLength); @@ -255,6 +262,7 @@ public class NetworkUtils { * @throws IllegalArgumentException the specified netmask was not contiguous. * @hide */ + @UnsupportedAppUsage public static int netmaskToPrefixLength(Inet4Address netmask) { // inetAddressToInt returns an int in *network* byte order. int i = Integer.reverseBytes(inetAddressToInt(netmask)); @@ -275,6 +283,7 @@ public class NetworkUtils { * @return the InetAddress * @hide */ + @UnsupportedAppUsage public static InetAddress numericToInetAddress(String addrString) throws IllegalArgumentException { return InetAddress.parseNumericAddress(addrString); @@ -349,6 +358,7 @@ public class NetworkUtils { /** * Returns the implicit netmask of an IPv4 address, as was the custom before 1993. */ + @UnsupportedAppUsage public static int getImplicitNetmask(Inet4Address address) { int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value. if (firstByte < 128) { @@ -439,6 +449,7 @@ public class NetworkUtils { * @param addr a string representing an ip addr * @return a string propertly trimmed */ + @UnsupportedAppUsage public static String trimV4AddrZeros(String addr) { if (addr == null) return null; String[] octets = addr.split("\\."); diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index 5f5e6235eb..e926fda336 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -17,6 +17,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -91,6 +92,7 @@ public class ProxyInfo implements Parcelable { * Create a ProxyProperties that points at a HTTP Proxy. * @hide */ + @UnsupportedAppUsage public ProxyInfo(String host, int port, String exclList) { mHost = host; mPort = port; diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 90a2460ff2..3e73d3d2d9 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -55,6 +56,7 @@ public final class RouteInfo implements Parcelable { /** * The gateway address for this route. */ + @UnsupportedAppUsage private final InetAddress mGateway; /** @@ -79,6 +81,7 @@ public final class RouteInfo implements Parcelable { // Derived data members. // TODO: remove these. + @UnsupportedAppUsage private final boolean mIsHost; private final boolean mHasGateway; @@ -160,6 +163,7 @@ public final class RouteInfo implements Parcelable { /** * @hide */ + @UnsupportedAppUsage public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) { this(destination, gateway, iface, RTN_UNICAST); } @@ -167,6 +171,7 @@ public final class RouteInfo implements Parcelable { /** * @hide */ + @UnsupportedAppUsage public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { this(destination == null ? null : new IpPrefix(destination.getAddress(), destination.getPrefixLength()), @@ -197,6 +202,7 @@ public final class RouteInfo implements Parcelable { * * TODO: Remove this. */ + @UnsupportedAppUsage public RouteInfo(LinkAddress destination, InetAddress gateway) { this(destination, gateway, null); } @@ -208,6 +214,7 @@ public final class RouteInfo implements Parcelable { * * @hide */ + @UnsupportedAppUsage public RouteInfo(InetAddress gateway) { this((IpPrefix) null, gateway, null); } @@ -258,6 +265,7 @@ public final class RouteInfo implements Parcelable { } } + @UnsupportedAppUsage private boolean isHost() { return (mDestination.getAddress() instanceof Inet4Address && mDestination.getPrefixLength() == 32) || @@ -355,6 +363,7 @@ public final class RouteInfo implements Parcelable { * @return {@code true} if a gateway is specified * @hide */ + @UnsupportedAppUsage public boolean hasGateway() { return mHasGateway; } @@ -379,6 +388,7 @@ public final class RouteInfo implements Parcelable { * * @hide */ + @UnsupportedAppUsage public static RouteInfo selectBestRoute(Collection routes, InetAddress dest) { if ((routes == null) || (dest == null)) return null; diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java index 58b1b88d89..3aa56b9025 100644 --- a/core/java/android/net/StaticIpConfiguration.java +++ b/core/java/android/net/StaticIpConfiguration.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.net.LinkAddress; import android.os.Parcelable; import android.os.Parcel; @@ -46,11 +47,16 @@ import java.util.Objects; * @hide */ public class StaticIpConfiguration implements Parcelable { + @UnsupportedAppUsage public LinkAddress ipAddress; + @UnsupportedAppUsage public InetAddress gateway; + @UnsupportedAppUsage public final ArrayList dnsServers; + @UnsupportedAppUsage public String domains; + @UnsupportedAppUsage public StaticIpConfiguration() { dnsServers = new ArrayList(); } @@ -80,6 +86,7 @@ public class StaticIpConfiguration implements Parcelable { * route to the gateway as well. This configuration is arguably invalid, but it used to work * in K and earlier, and other OSes appear to accept it. */ + @UnsupportedAppUsage public List getRoutes(String iface) { List routes = new ArrayList(3); if (ipAddress != null) { From 2622bdf5698ff06b21f93f37e5391cf3538ca150 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Fri, 14 Sep 2018 12:35:36 +0100 Subject: [PATCH 003/130] Move some members to the "Q blacklist". Based on some analysis, these fields/methods are likely false positives. Set maxTargetSdk=P so that any apps using them are required to migrate off them in future. See the bug for more details. Exempted-From-Owner-Approval: Automatic changes to the codebase affecting only @UnsupportedAppUsage annotations, themselves added without requiring owners approval earlier. Bug: 115609023 Test: m Change-Id: I719b5c94e5b1f4fa562dd5d655953422958ad37e --- core/java/android/net/NetworkCapabilities.java | 3 ++- core/java/android/net/NetworkState.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index fd1e5f2338..12b6f9e1b3 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -21,6 +21,7 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.net.ConnectivityManager.NetworkCallback; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; @@ -904,7 +905,7 @@ public final class NetworkCapabilities implements Parcelable { * specifier. See {@link #setNetworkSpecifier}. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public NetworkSpecifier getNetworkSpecifier() { return mNetworkSpecifier; } diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index c545ee205d..97fb3fb772 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.Slog; @@ -34,7 +35,7 @@ public class NetworkState implements Parcelable { public final NetworkInfo networkInfo; public final LinkProperties linkProperties; public final NetworkCapabilities networkCapabilities; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final Network network; public final String subscriberId; public final String networkId; From 3300b0bda8db036dae7f52920a1a3856a7766cb7 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 28 Sep 2018 14:33:11 +0900 Subject: [PATCH 004/130] Call clearSettingsProvider before and after test FakeSettingsProvider requires this method to be called before and after use. Without this, the settings value or content provider may be cached statically, so the test will be affected by code accessing settings before it is run. Bug: b/116668105 Test: atest FrameworksNetTests Change-Id: I1480f3f3bbb17791752582a70327bb5c7c348d7c (cherry picked from commit b7c67f8e24ae387ce8068f6466623f07323c24f0) --- .../com/android/server/ConnectivityServiceTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index e3db7e8a13..fceaabddfe 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -79,6 +79,7 @@ import static org.mockito.Mockito.when; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -248,7 +249,7 @@ public class ConnectivityServiceTest { @Spy private Resources mResources; private final LinkedBlockingQueue mStartedActivities = new LinkedBlockingQueue<>(); - MockContext(Context base) { + MockContext(Context base, ContentProvider settingsProvider) { super(base); mResources = spy(base.getResources()); @@ -260,7 +261,7 @@ public class ConnectivityServiceTest { }); mContentResolver = new MockContentResolver(); - mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); + mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider); } @Override @@ -1048,7 +1049,9 @@ public class ConnectivityServiceTest { Looper.prepare(); } - mServiceContext = new MockContext(InstrumentationRegistry.getContext()); + FakeSettingsProvider.clearSettingsProvider(); + mServiceContext = new MockContext(InstrumentationRegistry.getContext(), + new FakeSettingsProvider()); LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); LocalServices.addService( NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class)); @@ -1086,6 +1089,7 @@ public class ConnectivityServiceTest { mEthernetNetworkAgent.disconnect(); mEthernetNetworkAgent = null; } + FakeSettingsProvider.clearSettingsProvider(); } private static int transportToLegacyType(int transport) { From f0254b73261729ff76792654b6133cb217db0b6b Mon Sep 17 00:00:00 2001 From: Andrew Solovay Date: Tue, 2 Oct 2018 14:14:42 -0700 Subject: [PATCH 005/130] cherry-pick from pi-dev docs: Replacing {#link with {@link Several java files had the typo {#link (for cross-references to other Javadocs) instead of the proper {@link format. This was confusing the new doc publish tool (Mivi) since that's the format used for {# Django comments #}. Fixed a couple of links that had other errors (which prevented building once the {# -> {@ was done) and other typos. Replaced throughout the frameworks/base project; I'll need a separate CL for the AndroidX fixes. (Other files were not in the public Javadocs.) Bug: 111925950 Test: make ds-docs Change-Id: Ia06e1fffd814671289a1caebd5962aedc18a28d7 Original Change-Id: Ia06e1fffd814671289a1caebd5962aedc18a28d7 Exempt-From-Owner-Approval: Docs-only change --- core/java/android/net/NetworkMisc.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java index 69f50a272a..a2da6eaa49 100644 --- a/core/java/android/net/NetworkMisc.java +++ b/core/java/android/net/NetworkMisc.java @@ -46,7 +46,7 @@ public class NetworkMisc implements Parcelable { /** * Set if the user desires to use this network even if it is unvalidated. This field has meaning - * only if {#link explicitlySelected} is true. If it is, this field must also be set to the + * only if {@link explicitlySelected} is true. If it is, this field must also be set to the * appropriate value based on previous user choice. */ public boolean acceptUnvalidated; From 120511dbeb20a0566c1f6eee3aa769f49fa65f8d Mon Sep 17 00:00:00 2001 From: Eran Messeri Date: Thu, 20 Sep 2018 15:15:41 +0100 Subject: [PATCH 006/130] Enterprise Policy for Private DNS Setting A new API for setting the Private DNS settings value programatically via the DevicePolicyManager. Since there are two separate settings for Private DNS, and the value provided for the hostname needs to be validated, a new DevicePolicyManager API is introduced. Only a Device Policy Client in Device Owner mode may change these settings. The DPC may additionally set a user restriction (added in a separate CL) to prevent the user from changing Private DNS settings. Bug: 112982691 Test: atest com.android.cts.devicepolicy.DeviceOwnerTest#testPrivateDnsPolicy Change-Id: I566437e4fe10e1346858149120c50b3c20ca073f --- core/java/android/net/NetworkUtils.java | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 34e9476b3e..c431e40ede 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -16,8 +16,13 @@ package android.net; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; +import android.system.Os; import android.util.Log; import android.util.Pair; @@ -570,4 +575,30 @@ public class NetworkUtils { } return routedIPCount; } + + private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6}; + + /** + * Returns true if the hostname is weakly validated. + * @param hostname Name of host to validate. + * @return True if it's a valid-ish hostname. + * + * @hide + */ + public static boolean isWeaklyValidatedHostname(@NonNull String hostname) { + // TODO(b/34953048): Use a validation method that permits more accurate, + // but still inexpensive, checking of likely valid DNS hostnames. + final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$"; + if (!hostname.matches(weakHostnameRegex)) { + return false; + } + + for (int address_family : ADDRESS_FAMILIES) { + if (Os.inet_pton(address_family, hostname) != null) { + return false; + } + } + + return true; + } } From e26dae35e72617dea246be29b60f7815eb092c21 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Fri, 5 Oct 2018 09:42:19 -0700 Subject: [PATCH 007/130] wifi(API): NetworkSpecifier for Wifi NetworkAgent Create an @hide NetworkSpecifier to use by the Wifi NetworkAgent. This will be used by connectivity service to match the incoming NetworkRequest (with WifiNetworkSpecifier) with the NetworkAgent we created to serve that request. The WifiNetworkAgentSpecifier will hold the current connected wifi network configuration which will be used to pattern match the WifiNetworkSpecifier from NetworkRequest's. Also, added a @hide helper method in MacAddress to help with matching bssid pattern. Bug: 113878056 Test: Unit tests Change-Id: I9a643f0b914d48ff64104c798ec2869db40cb24b --- core/java/android/net/MacAddress.java | 15 ++++++++ .../net/java/android/net/MacAddressTest.java | 35 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 98f356722b..4cd000113b 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -393,4 +393,19 @@ public final class MacAddress implements Parcelable { } return out; } + + /** + * Checks if this MAC Address matches the provided range. + * + * @param baseAddress MacAddress representing the base address to compare with. + * @param mask MacAddress representing the mask to use during comparison. + * @return true if this MAC Address matches the given range. + * + * @hide + */ + public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) { + Preconditions.checkNotNull(baseAddress); + Preconditions.checkNotNull(mask); + return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr); + } } diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java index 04266c5b3a..b9222a86a0 100644 --- a/tests/net/java/android/net/MacAddressTest.java +++ b/tests/net/java/android/net/MacAddressTest.java @@ -17,8 +17,8 @@ package android.net; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.support.test.filters.SmallTest; @@ -252,6 +252,39 @@ public class MacAddressTest { } } + @Test + public void testMatches() { + // match 4 bytes prefix + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:00:00"), + MacAddress.fromString("ff:ff:ff:ff:00:00"))); + + // match bytes 0,1,2 and 5 + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:00:00:11"), + MacAddress.fromString("ff:ff:ff:00:00:ff"))); + + // match 34 bit prefix + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:c0:00"), + MacAddress.fromString("ff:ff:ff:ff:c0:00"))); + + // fail to match 36 bit prefix + assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:40:00"), + MacAddress.fromString("ff:ff:ff:ff:f0:00"))); + + // match all 6 bytes + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("aa:bb:cc:dd:ee:11"), + MacAddress.fromString("ff:ff:ff:ff:ff:ff"))); + + // match none of 6 bytes + assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches( + MacAddress.fromString("00:00:00:00:00:00"), + MacAddress.fromString("00:00:00:00:00:00"))); + } + static byte[] toByteArray(int... in) { byte[] out = new byte[in.length]; for (int i = 0; i < in.length; i++) { From 42ab31a79801dde5b6e6bee1e036f5e9d69e7144 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Fri, 2 Nov 2018 15:07:20 -0700 Subject: [PATCH 008/130] Add IPv6 link-local address generation from EUI-48 Add a utility method to convert an EUI-48 to an IPv6 link-local address based on RFC 4291 (EUI-64 generation) followed by RFC 4862. Bug: 117605977 Test: atest MacAddressTest Change-Id: I80b683e69da6beff3b37fc345fc15aa9610d09b7 --- core/java/android/net/MacAddress.java | 33 +++++++++++++++++++ .../net/java/android/net/MacAddressTest.java | 21 ++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 4cd000113b..4e55175619 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -18,6 +18,7 @@ package android.net; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -27,6 +28,8 @@ import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.net.Inet6Address; +import java.net.UnknownHostException; import java.security.SecureRandom; import java.util.Arrays; import java.util.Random; @@ -408,4 +411,34 @@ public final class MacAddress implements Parcelable { Preconditions.checkNotNull(mask); return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr); } + + /** + * Create a link-local Inet6Address from the MAC address. The EUI-48 MAC address is converted + * to an EUI-64 MAC address per RFC 4291. The resulting EUI-64 is used to construct a link-local + * IPv6 address per RFC 4862. + * + * @return A link-local Inet6Address constructed from the MAC address. + * @hide + */ + public @Nullable Inet6Address getLinkLocalIpv6FromEui48Mac() { + byte[] macEui48Bytes = toByteArray(); + byte[] addr = new byte[16]; + + addr[0] = (byte) 0xfe; + addr[1] = (byte) 0x80; + addr[8] = (byte) (macEui48Bytes[0] ^ (byte) 0x02); // flip the link-local bit + addr[9] = macEui48Bytes[1]; + addr[10] = macEui48Bytes[2]; + addr[11] = (byte) 0xff; + addr[12] = (byte) 0xfe; + addr[13] = macEui48Bytes[3]; + addr[14] = macEui48Bytes[4]; + addr[15] = macEui48Bytes[5]; + + try { + return Inet6Address.getByAddress(null, addr, 0); + } catch (UnknownHostException e) { + return null; + } + } } diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java index b9222a86a0..17486e09bc 100644 --- a/tests/net/java/android/net/MacAddressTest.java +++ b/tests/net/java/android/net/MacAddressTest.java @@ -16,6 +16,7 @@ package android.net; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -24,12 +25,13 @@ import static org.junit.Assert.fail; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import java.util.Arrays; -import java.util.Random; - import org.junit.Test; import org.junit.runner.RunWith; +import java.net.Inet6Address; +import java.util.Arrays; +import java.util.Random; + @SmallTest @RunWith(AndroidJUnit4.class) public class MacAddressTest { @@ -285,6 +287,19 @@ public class MacAddressTest { MacAddress.fromString("00:00:00:00:00:00"))); } + /** + * Tests that link-local address generation from MAC is valid. + */ + @Test + public void testLinkLocalFromMacGeneration() { + MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f"); + byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x74, + (byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f}; + Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac(); + assertTrue(llv6.isLinkLocalAddress()); + assertArrayEquals(inet6ll, llv6.getAddress()); + } + static byte[] toByteArray(int... in) { byte[] out = new byte[in.length]; for (int i = 0; i < in.length; i++) { From 476352b00a02ce0502ed8b42ba73463ecabaaec1 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 14 Nov 2018 22:04:17 -0800 Subject: [PATCH 009/130] Move hidden APIs into system APIs To allow vendor code to construct LinkAddress, which is one of the parameter in the system API DataCallResponse. Test: Build Bug: 73659459 Change-Id: I3e203781d3a03285fa0e047cc8837ccb4a09016a --- core/java/android/net/LinkAddress.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 1bc0d327ab..77562dbd7b 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -25,6 +25,7 @@ import static android.system.OsConstants.RT_SCOPE_LINK; import static android.system.OsConstants.RT_SCOPE_SITE; import static android.system.OsConstants.RT_SCOPE_UNIVERSE; +import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -167,7 +168,7 @@ public class LinkAddress implements Parcelable { * @param prefixLength The prefix length. * @hide */ - @UnsupportedAppUsage + @SystemApi public LinkAddress(InetAddress address, int prefixLength) { this(address, prefixLength, 0, 0); this.scope = scopeForUnicastAddress(address); @@ -190,7 +191,7 @@ public class LinkAddress implements Parcelable { * @param string The string to parse. * @hide */ - @UnsupportedAppUsage + @SystemApi public LinkAddress(String address) { this(address, 0, 0); this.scope = scopeForUnicastAddress(this.address); From de679608ef3503623a6c161d3be4046a3eaaef5b Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Thu, 20 Dec 2018 13:53:36 +0000 Subject: [PATCH 010/130] Limit access to suspected false positives. Members modified herein are suspected to be false positives: i.e. things that were added to the greylist in P, but subsequent data analysis suggests that they are not, in fact, used after all. Add a maxTargetSdk=P to these APIs. This is lower-risk that simply removing these things from the greylist, as none of out data sources are perfect nor complete. For APIs that are not supported yet by annotations, move them to hiddenapi-greylist-max-p.txt instead which has the same effect. Exempted-From-Owner-Approval: Automatic changes to the codebase affecting only @UnsupportedAppUsage annotations, themselves added without requiring owners approval earlier. Bug: 115609023 Test: m Change-Id: I020a9c09672ebcae64c5357abc4993e07e744687 --- core/java/android/net/ConnectivityManager.java | 3 ++- core/java/android/net/LinkAddress.java | 5 +++-- core/java/android/net/LinkProperties.java | 5 +++-- core/java/android/net/NetworkAgent.java | 3 ++- core/java/android/net/NetworkRequest.java | 3 ++- core/java/android/net/RouteInfo.java | 5 +++-- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 49c3dc63e1..61d5a91277 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -27,6 +27,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Binder; +import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Handler; @@ -2768,7 +2769,7 @@ public class ConnectivityManager { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void unregisterNetworkFactory(Messenger messenger) { try { mService.unregisterNetworkFactory(messenger); diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 77562dbd7b..b40f15ae17 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -27,6 +27,7 @@ import static android.system.OsConstants.RT_SCOPE_UNIVERSE; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.Pair; @@ -56,13 +57,13 @@ public class LinkAddress implements Parcelable { /** * IPv4 or IPv6 address. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private InetAddress address; /** * Prefix length. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private int prefixLength; /** diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 80517ce28c..3a79206515 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -50,7 +51,7 @@ import java.util.StringJoiner; */ public final class LinkProperties implements Parcelable { // The interface described by the network link. - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private String mIfaceName; private ArrayList mLinkAddresses = new ArrayList<>(); private ArrayList mDnses = new ArrayList<>(); @@ -1136,7 +1137,7 @@ public final class LinkProperties implements Parcelable { * @return {@code true} if both are identical, {@code false} otherwise. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean isIdenticalHttpProxy(LinkProperties target) { return getHttpProxy() == null ? target.getHttpProxy() == null : getHttpProxy().equals(target.getHttpProxy()); diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 114b423c31..99bfc140f1 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -19,6 +19,7 @@ package android.net; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.ConnectivityManager.PacketKeepalive; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -352,7 +353,7 @@ public abstract class NetworkAgent extends Handler { /** * Called by the bearer code when it has new NetworkInfo data. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public void sendNetworkInfo(NetworkInfo networkInfo) { queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); } diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 3b01b03edd..9508217be5 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -21,6 +21,7 @@ import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.net.NetworkCapabilities.NetCapability; import android.net.NetworkCapabilities.Transport; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; @@ -57,7 +58,7 @@ public class NetworkRequest implements Parcelable { * Causes CONNECTIVITY_ACTION broadcasts to be sent. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public final int legacyType; /** diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 3e73d3d2d9..37ab9ffb1f 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -81,7 +82,7 @@ public final class RouteInfo implements Parcelable { // Derived data members. // TODO: remove these. - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final boolean mIsHost; private final boolean mHasGateway; @@ -265,7 +266,7 @@ public final class RouteInfo implements Parcelable { } } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private boolean isHost() { return (mDestination.getAddress() instanceof Inet4Address && mDestination.getPrefixLength() == 32) || From 2e4422598d15d5fa0699a69c0ca4cf24986ea5b8 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 21 Jan 2019 21:07:10 +0900 Subject: [PATCH 011/130] Add NetworkMonitor constants to SystemApi NetworkMonitor lives in the NetworkStack which must only use system APIs. This includes constants used by NetworkMonitor and captive portal login. Bug: 112869080 Test: m (Cherry-pick of aosp I4879568d3fbf9435767c8d4d0ab5198d421a2f4f) Change-Id: I8b5f0bb61c3ef0d2f33af7dd67b72ac6c5a1d1b5 --- core/java/android/net/CaptivePortal.java | 8 ++++++++ core/java/android/net/ConnectivityManager.java | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java index ee05f2832a..4047068f1c 100644 --- a/core/java/android/net/CaptivePortal.java +++ b/core/java/android/net/CaptivePortal.java @@ -15,6 +15,8 @@ */ package android.net; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -28,10 +30,16 @@ import android.os.RemoteException; */ public class CaptivePortal implements Parcelable { /** @hide */ + @SystemApi + @TestApi public static final int APP_RETURN_DISMISSED = 0; /** @hide */ + @SystemApi + @TestApi public static final int APP_RETURN_UNWANTED = 1; /** @hide */ + @SystemApi + @TestApi public static final int APP_RETURN_WANTED_AS_IS = 2; private final IBinder mBinder; diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index abc00feeb2..cee3a409fc 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -23,6 +23,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; import android.content.Context; @@ -255,6 +256,8 @@ public class ConnectivityManager { * portal login activity. * {@hide} */ + @SystemApi + @TestApi public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC"; @@ -262,6 +265,8 @@ public class ConnectivityManager { * Key for passing a user agent string to the captive portal login activity. * {@hide} */ + @SystemApi + @TestApi public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; From e761c0b364b3d1bbd895cc192a867743b21533c1 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 21 Jan 2019 23:36:53 +0900 Subject: [PATCH 012/130] Migrate ICaptivePortal to stable AIDL Also add required API for the captive portal app to stop using hidden members. Test: atest FrameworksNetTests NetworkStackTests Bug: 112869080 Change-Id: I62b457e709fa199822bb8f80b0eab990be4ded93 --- core/java/android/net/CaptivePortal.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java index 4047068f1c..3b01266737 100644 --- a/core/java/android/net/CaptivePortal.java +++ b/core/java/android/net/CaptivePortal.java @@ -45,6 +45,8 @@ public class CaptivePortal implements Parcelable { private final IBinder mBinder; /** @hide */ + @SystemApi + @TestApi public CaptivePortal(IBinder binder) { mBinder = binder; } @@ -107,6 +109,8 @@ public class CaptivePortal implements Parcelable { * connectivity for apps because the captive portal is still in place. * @hide */ + @SystemApi + @TestApi public void useNetwork() { try { ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_WANTED_AS_IS); From daace816dbb609a3cbe8d188e779d5f26357d584 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 24 Jan 2019 00:55:43 +0900 Subject: [PATCH 013/130] Add additional SystemApi for NetworkStack Members in this CL were missed in earlier changes. Test: m Bug: 112869080 Change-Id: I8b5b80ea7b267357eb0387d504a2f78358d6d502 --- core/java/android/net/IpPrefix.java | 4 ++++ core/java/android/net/LinkAddress.java | 2 ++ core/java/android/net/LinkProperties.java | 11 ++++++++++- core/java/android/net/RouteInfo.java | 2 ++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java index 4631c56596..b996cdab51 100644 --- a/core/java/android/net/IpPrefix.java +++ b/core/java/android/net/IpPrefix.java @@ -16,6 +16,8 @@ package android.net; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import android.util.Pair; @@ -83,6 +85,8 @@ public final class IpPrefix implements Parcelable { * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). * @hide */ + @SystemApi + @TestApi public IpPrefix(InetAddress address, 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. diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index a536d08876..fbd602c7b2 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -162,6 +162,8 @@ public class LinkAddress implements Parcelable { * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}). * @hide */ + @SystemApi + @TestApi public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) { init(address, prefixLength, flags, scope); } diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 21b6a8eb19..662870182e 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -174,7 +174,8 @@ public final class LinkProperties implements Parcelable { /** * @hide */ - @UnsupportedAppUsage + @SystemApi + @TestApi public LinkProperties(LinkProperties source) { if (source != null) { mIfaceName = source.mIfaceName; @@ -576,6 +577,8 @@ public final class LinkProperties implements Parcelable { * @param addresses The {@link Collection} of PCSCF servers to set in this object. * @hide */ + @SystemApi + @TestApi public void setPcscfServers(Collection pcscfServers) { mPcscfs.clear(); for (InetAddress pcscfServer: pcscfServers) { @@ -590,6 +593,8 @@ public final class LinkProperties implements Parcelable { * this link. * @hide */ + @SystemApi + @TestApi public List getPcscfServers() { return Collections.unmodifiableList(mPcscfs); } @@ -781,6 +786,8 @@ public final class LinkProperties implements Parcelable { * @return the NAT64 prefix. * @hide */ + @SystemApi + @TestApi public @Nullable IpPrefix getNat64Prefix() { return mNat64Prefix; } @@ -794,6 +801,8 @@ public final class LinkProperties implements Parcelable { * @param prefix the NAT64 prefix. * @hide */ + @SystemApi + @TestApi public void setNat64Prefix(IpPrefix prefix) { if (prefix != null && prefix.getPrefixLength() != 96) { throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix); diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 6bf2c67da9..5c0f758209 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -110,6 +110,8 @@ public final class RouteInfo implements Parcelable { * * @hide */ + @SystemApi + @TestApi public RouteInfo(IpPrefix destination, InetAddress gateway, String iface, int type) { switch (type) { case RTN_UNICAST: From 58e8be00ee9631f72fbe79d45f4e10eb3aeaf9bf Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Wed, 5 Dec 2018 10:40:23 +0000 Subject: [PATCH 014/130] Whitelist packages from VPN lockdown. Bug: 77468593 Test: atest com.android.server.connectivity.VpnTest Test: atest MixedDeviceOwnerTest#testAlwaysOnVpn Test: MixedDeviceOwnerTest#testAlwaysOnVpnAcrossReboot Change-Id: I7f6c5b9172063b588feacd6b9930a6cb88f764ab --- .../java/android/net/ConnectivityManager.java | 41 ++++++- .../android/net/IConnectivityManager.aidl | 5 +- .../android/server/ConnectivityService.java | 57 ++++++++-- .../android/server/connectivity/VpnTest.java | 103 ++++++++++++++++-- 4 files changed, 186 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index cee3a409fc..e53f883c47 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1007,14 +1007,20 @@ public class ConnectivityManager { * to remove an existing always-on VPN configuration. * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or * {@code false} otherwise. + * @param lockdownWhitelist The list of packages that are allowed to access network directly + * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so + * this method must be called when a package that should be whitelisted is installed or + * uninstalled. * @return {@code true} if the package is set as always-on VPN controller; * {@code false} otherwise. * @hide */ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage, - boolean lockdownEnabled) { + boolean lockdownEnabled, @Nullable List lockdownWhitelist) { try { - return mService.setAlwaysOnVpnPackage(userId, vpnPackage, lockdownEnabled); + return mService.setAlwaysOnVpnPackage( + userId, vpnPackage, lockdownEnabled, lockdownWhitelist); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1029,6 +1035,7 @@ public class ConnectivityManager { * or {@code null} if none is set. * @hide */ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) public String getAlwaysOnVpnPackageForUser(int userId) { try { return mService.getAlwaysOnVpnPackage(userId); @@ -1037,6 +1044,36 @@ public class ConnectivityManager { } } + /** + * @return whether always-on VPN is in lockdown mode. + * + * @hide + **/ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) + public boolean isVpnLockdownEnabled(int userId) { + try { + return mService.isVpnLockdownEnabled(userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + } + + /** + * @return the list of packages that are allowed to access network when always-on VPN is in + * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active. + * + * @hide + **/ + @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) + public List getVpnLockdownWhitelist(int userId) { + try { + return mService.getVpnLockdownWhitelist(userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Returns details about the currently active default data network * for a given uid. This is for internal use only to avoid spying diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 3d34574440..ac6b5b81b5 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -125,8 +125,11 @@ interface IConnectivityManager boolean updateLockdownVpn(); boolean isAlwaysOnVpnPackageSupported(int userId, String packageName); - boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown); + boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown, + in List lockdownWhitelist); String getAlwaysOnVpnPackage(int userId); + boolean isVpnLockdownEnabled(int userId); + List getVpnLockdownWhitelist(int userId); int checkMobileProvisioning(int suggestedTimeOutMs); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 919a5ab4ee..c749141625 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1869,6 +1869,12 @@ public class ConnectivityService extends IConnectivityManager.Stub "ConnectivityService"); } + private void enforceControlAlwaysOnVpnPermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CONTROL_ALWAYS_ON_VPN, + "ConnectivityService"); + } + private void enforceNetworkStackSettingsOrSetup() { enforceAnyPermissionOf( android.Manifest.permission.NETWORK_SETTINGS, @@ -1876,6 +1882,12 @@ public class ConnectivityService extends IConnectivityManager.Stub android.Manifest.permission.NETWORK_STACK); } + private void enforceNetworkStackPermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.NETWORK_STACK, + "ConnectivityService"); + } + private boolean checkNetworkStackPermission() { return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission( android.Manifest.permission.NETWORK_STACK); @@ -4069,8 +4081,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown) { - enforceConnectivityInternalPermission(); + public boolean setAlwaysOnVpnPackage( + int userId, String packageName, boolean lockdown, List lockdownWhitelist) { + enforceControlAlwaysOnVpnPermission(); enforceCrossUserPermission(userId); synchronized (mVpns) { @@ -4084,11 +4097,11 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.w(TAG, "User " + userId + " has no Vpn configuration"); return false; } - if (!vpn.setAlwaysOnPackage(packageName, lockdown)) { + if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist)) { return false; } if (!startAlwaysOnVpn(userId)) { - vpn.setAlwaysOnPackage(null, false); + vpn.setAlwaysOnPackage(null, false, null); return false; } } @@ -4097,7 +4110,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String getAlwaysOnVpnPackage(int userId) { - enforceConnectivityInternalPermission(); + enforceControlAlwaysOnVpnPermission(); enforceCrossUserPermission(userId); synchronized (mVpns) { @@ -4110,6 +4123,36 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + @Override + public boolean isVpnLockdownEnabled(int userId) { + enforceControlAlwaysOnVpnPermission(); + enforceCrossUserPermission(userId); + + synchronized (mVpns) { + Vpn vpn = mVpns.get(userId); + if (vpn == null) { + Slog.w(TAG, "User " + userId + " has no Vpn configuration"); + return false; + } + return vpn.getLockdown(); + } + } + + @Override + public List getVpnLockdownWhitelist(int userId) { + enforceControlAlwaysOnVpnPermission(); + enforceCrossUserPermission(userId); + + synchronized (mVpns) { + Vpn vpn = mVpns.get(userId); + if (vpn == null) { + Slog.w(TAG, "User " + userId + " has no Vpn configuration"); + return null; + } + return vpn.getLockdownWhitelist(); + } + } + @Override public int checkMobileProvisioning(int suggestedTimeOutMs) { // TODO: Remove? Any reason to trigger a provisioning check? @@ -4339,7 +4382,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) { Slog.d(TAG, "Removing always-on VPN package " + packageName + " for user " + userId); - vpn.setAlwaysOnPackage(null, false); + vpn.setAlwaysOnPackage(null, false, null); } } } @@ -6208,7 +6251,7 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mVpns) { final String alwaysOnPackage = getAlwaysOnVpnPackage(userId); if (alwaysOnPackage != null) { - setAlwaysOnVpnPackage(userId, null, false); + setAlwaysOnVpnPackage(userId, null, false, null); setVpnPackageAuthorization(alwaysOnPackage, userId, false); } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 0b74d878f0..5b17224e41 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -246,17 +246,17 @@ public class VpnTest { assertFalse(vpn.getLockdown()); // Set always-on without lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList())); assertTrue(vpn.getAlwaysOn()); assertFalse(vpn.getLockdown()); // Set always-on with lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList())); assertTrue(vpn.getAlwaysOn()); assertTrue(vpn.getLockdown()); // Remove always-on configuration. - assertTrue(vpn.setAlwaysOnPackage(null, false)); + assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList())); assertFalse(vpn.getAlwaysOn()); assertFalse(vpn.getLockdown()); } @@ -270,11 +270,11 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on without lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null)); assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on with lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null)); verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[1] - 1), new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) @@ -283,7 +283,7 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[1]); // Switch to another app. - assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[1] - 1), new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) @@ -296,6 +296,87 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[3]); } + @Test + public void testLockdownWhitelist() throws Exception { + final Vpn vpn = createVpn(primaryUser.id); + final UidRange user = UidRange.createForUser(primaryUser.id); + + // Set always-on with lockdown and whitelist app PKGS[2] from lockdown. + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[2]))); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { + new UidRange(user.start, user.start + PKG_UIDS[1] - 1), + new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) + })); + assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); + + // Change whitelisted app to PKGS[3]. + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[3]))); + verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) + })); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1), + new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) + })); + assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]); + assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]); + + // Change the VPN app. + assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[3]))); + verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { + new UidRange(user.start, user.start + PKG_UIDS[1] - 1), + new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1) + })); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { + new UidRange(user.start, user.start + PKG_UIDS[0] - 1), + new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1) + })); + assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); + assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); + + // Remove the whitelist. + assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null)); + verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1), + new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) + })); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[0] + 1, user.stop), + })); + assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], + user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[0]); + + // Add the whitelist. + assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[1]))); + verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[0] + 1, user.stop) + })); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { + new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), + new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) + })); + assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); + assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]); + + // Try whitelisting a package with a comma, should be rejected. + assertFalse(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList("a.b,c.d"))); + + // Pass a non-existent packages in the whitelist, they (and only they) should be ignored. + // Whitelisted package should change from PGKS[1] to PKGS[2]. + assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, + Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"))); + verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{ + new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), + new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) + })); + verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{ + new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1), + new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) + })); + } + @Test public void testLockdownAddingAProfile() throws Exception { final Vpn vpn = createVpn(primaryUser.id); @@ -310,7 +391,7 @@ public class VpnTest { final UidRange profile = UidRange.createForUser(tempProfile.id); // Set lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null)); verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[3] - 1), new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) @@ -436,7 +517,7 @@ public class VpnTest { .cancelAsUser(anyString(), anyInt(), eq(userHandle)); // Start showing a notification for disconnected once always-on. - vpn.setAlwaysOnPackage(PKGS[0], false); + vpn.setAlwaysOnPackage(PKGS[0], false, null); order.verify(mNotificationManager) .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle)); @@ -450,7 +531,7 @@ public class VpnTest { .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle)); // Notification should be cleared after unsetting always-on package. - vpn.setAlwaysOnPackage(null, false); + vpn.setAlwaysOnPackage(null, false, null); order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle)); } @@ -583,7 +664,9 @@ public class VpnTest { doAnswer(invocation -> { final String appName = (String) invocation.getArguments()[0]; final int userId = (int) invocation.getArguments()[1]; - return UserHandle.getUid(userId, packages.get(appName)); + Integer appId = packages.get(appName); + if (appId == null) throw new PackageManager.NameNotFoundException(appName); + return UserHandle.getUid(userId, appId); }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt()); } catch (Exception e) { } From 8767f41688f3807767024c9e30d6479a464ae6c8 Mon Sep 17 00:00:00 2001 From: Irina Dumitrescu Date: Wed, 5 Dec 2018 16:19:47 +0000 Subject: [PATCH 015/130] Add API for proxy configuration over VPN. Test: runtest -x frameworks/base/tests/net/java/com/android/server/ConnectivityServiceTest.java && atest HostsideVpnTests Bug: 76001058 Change-Id: Id4dde4a4103fd93bfbbacc52d0e5ade56ae67a6a --- core/java/android/net/ProxyInfo.java | 57 ++++++------ .../android/server/ConnectivityService.java | 73 ++++++++++----- .../server/connectivity/ProxyTracker.java | 18 ---- .../server/ConnectivityServiceTest.java | 92 +++++++++++++++++++ 4 files changed, 175 insertions(+), 65 deletions(-) diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index e926fda336..ef2269a145 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -39,12 +39,12 @@ import java.util.Locale; */ public class ProxyInfo implements Parcelable { - private String mHost; - private int mPort; - private String mExclusionList; - private String[] mParsedExclusionList; + private final String mHost; + private final int mPort; + private final String mExclusionList; + private final String[] mParsedExclusionList; + private final Uri mPacFileUrl; - private Uri mPacFileUrl; /** *@hide */ @@ -96,7 +96,8 @@ public class ProxyInfo implements Parcelable { public ProxyInfo(String host, int port, String exclList) { mHost = host; mPort = port; - setExclusionList(exclList); + mExclusionList = exclList; + mParsedExclusionList = parseExclusionList(mExclusionList); mPacFileUrl = Uri.EMPTY; } @@ -107,7 +108,8 @@ public class ProxyInfo implements Parcelable { public ProxyInfo(Uri pacFileUrl) { mHost = LOCAL_HOST; mPort = LOCAL_PORT; - setExclusionList(LOCAL_EXCL_LIST); + mExclusionList = LOCAL_EXCL_LIST; + mParsedExclusionList = parseExclusionList(mExclusionList); if (pacFileUrl == null) { throw new NullPointerException(); } @@ -121,7 +123,8 @@ public class ProxyInfo implements Parcelable { public ProxyInfo(String pacFileUrl) { mHost = LOCAL_HOST; mPort = LOCAL_PORT; - setExclusionList(LOCAL_EXCL_LIST); + mExclusionList = LOCAL_EXCL_LIST; + mParsedExclusionList = parseExclusionList(mExclusionList); mPacFileUrl = Uri.parse(pacFileUrl); } @@ -132,13 +135,22 @@ public class ProxyInfo implements Parcelable { public ProxyInfo(Uri pacFileUrl, int localProxyPort) { mHost = LOCAL_HOST; mPort = localProxyPort; - setExclusionList(LOCAL_EXCL_LIST); + mExclusionList = LOCAL_EXCL_LIST; + mParsedExclusionList = parseExclusionList(mExclusionList); if (pacFileUrl == null) { throw new NullPointerException(); } mPacFileUrl = pacFileUrl; } + private static String[] parseExclusionList(String exclusionList) { + if (exclusionList == null) { + return new String[0]; + } else { + return exclusionList.toLowerCase(Locale.ROOT).split(","); + } + } + private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) { mHost = host; mPort = port; @@ -159,6 +171,10 @@ public class ProxyInfo implements Parcelable { mExclusionList = source.getExclusionListAsString(); mParsedExclusionList = source.mParsedExclusionList; } else { + mHost = null; + mPort = 0; + mExclusionList = null; + mParsedExclusionList = null; mPacFileUrl = Uri.EMPTY; } } @@ -214,24 +230,14 @@ public class ProxyInfo implements Parcelable { return mExclusionList; } - // comma separated - private void setExclusionList(String exclusionList) { - mExclusionList = exclusionList; - if (mExclusionList == null) { - mParsedExclusionList = new String[0]; - } else { - mParsedExclusionList = exclusionList.toLowerCase(Locale.ROOT).split(","); - } - } - /** * @hide */ public boolean isValid() { if (!Uri.EMPTY.equals(mPacFileUrl)) return true; return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, - mPort == 0 ? "" : Integer.toString(mPort), - mExclusionList == null ? "" : mExclusionList); + mPort == 0 ? "" : Integer.toString(mPort), + mExclusionList == null ? "" : mExclusionList); } /** @@ -262,7 +268,7 @@ public class ProxyInfo implements Parcelable { sb.append("] "); sb.append(Integer.toString(mPort)); if (mExclusionList != null) { - sb.append(" xl=").append(mExclusionList); + sb.append(" xl=").append(mExclusionList); } } else { sb.append("[ProxyProperties.mHost == null]"); @@ -308,8 +314,8 @@ public class ProxyInfo implements Parcelable { */ public int hashCode() { return ((null == mHost) ? 0 : mHost.hashCode()) - + ((null == mExclusionList) ? 0 : mExclusionList.hashCode()) - + mPort; + + ((null == mExclusionList) ? 0 : mExclusionList.hashCode()) + + mPort; } /** @@ -352,8 +358,7 @@ public class ProxyInfo implements Parcelable { } String exclList = in.readString(); String[] parsedExclList = in.readStringArray(); - ProxyInfo proxyProperties = - new ProxyInfo(host, port, exclList, parsedExclList); + ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList); return proxyProperties; } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d0666b98c0..9e29e9f98f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -506,7 +506,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // A helper object to track the current default HTTP proxy. ConnectivityService needs to tell // the world when it changes. - private final ProxyTracker mProxyTracker; + @VisibleForTesting + protected final ProxyTracker mProxyTracker; final private SettingsObserver mSettingsObserver; @@ -815,7 +816,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mPolicyManagerInternal = checkNotNull( LocalServices.getService(NetworkPolicyManagerInternal.class), "missing NetworkPolicyManagerInternal"); - mProxyTracker = new ProxyTracker(context, mHandler, EVENT_PROXY_HAS_CHANGED); + mProxyTracker = makeProxyTracker(); mNetd = NetdService.getInstance(); mKeyStore = KeyStore.getInstance(); @@ -981,6 +982,11 @@ public class ConnectivityService extends IConnectivityManager.Stub deps); } + @VisibleForTesting + protected ProxyTracker makeProxyTracker() { + return new ProxyTracker(mContext, mHandler, EVENT_PROXY_HAS_CHANGED); + } + private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) { final NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addCapability(NET_CAPABILITY_INTERNET); @@ -3674,20 +3680,46 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + /** + * Returns information about the proxy a certain network is using. If given a null network, it + * it will return the proxy for the bound network for the caller app or the default proxy if + * none. + * + * @param network the network we want to get the proxy information for. + * @return Proxy information if a network has a proxy configured, or otherwise null. + */ @Override public ProxyInfo getProxyForNetwork(Network network) { - if (network == null) return mProxyTracker.getDefaultProxy(); final ProxyInfo globalProxy = mProxyTracker.getGlobalProxy(); if (globalProxy != null) return globalProxy; - if (!NetworkUtils.queryUserAccess(Binder.getCallingUid(), network.netId)) return null; - // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which - // caller may not have. + if (network == null) { + // Get the network associated with the calling UID. + final Network activeNetwork = getActiveNetworkForUidInternal(Binder.getCallingUid(), + true); + if (activeNetwork == null) { + return null; + } + return getLinkPropertiesProxyInfo(activeNetwork); + } else if (queryUserAccess(Binder.getCallingUid(), network.netId)) { + // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which + // caller may not have. + return getLinkPropertiesProxyInfo(network); + } + // No proxy info available if the calling UID does not have network access. + return null; + } + + @VisibleForTesting + protected boolean queryUserAccess(int uid, int netId) { + return NetworkUtils.queryUserAccess(uid, netId); + } + + private ProxyInfo getLinkPropertiesProxyInfo(Network network) { final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); if (nai == null) return null; synchronized (nai) { - final ProxyInfo proxyInfo = nai.linkProperties.getHttpProxy(); - if (proxyInfo == null) return null; - return new ProxyInfo(proxyInfo); + final ProxyInfo linkHttpProxy = nai.linkProperties.getHttpProxy(); + return linkHttpProxy == null ? null : new ProxyInfo(linkHttpProxy); } } @@ -3711,11 +3743,10 @@ public class ConnectivityService extends IConnectivityManager.Stub mProxyTracker.setDefaultProxy(proxy); } - // If the proxy has changed from oldLp to newLp, resend proxy broadcast with default proxy. - // This method gets called when any network changes proxy, but the broadcast only ever contains - // the default proxy (even if it hasn't changed). - // TODO: Deprecate the broadcast extras as they aren't necessarily applicable in a multi-network - // world where an app might be bound to a non-default network. + // If the proxy has changed from oldLp to newLp, resend proxy broadcast. This method gets called + // when any network changes proxy. + // TODO: Remove usage of broadcast extras as they are deprecated and not applicable in a + // multi-network world where an app might be bound to a non-default network. private void updateProxy(LinkProperties newLp, LinkProperties oldLp) { ProxyInfo newProxyInfo = newLp == null ? null : newLp.getHttpProxy(); ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy(); @@ -5881,12 +5912,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } scheduleUnvalidatedPrompt(networkAgent); - if (networkAgent.isVPN()) { - // Temporarily disable the default proxy (not global). - mProxyTracker.setDefaultProxyEnabled(false); - // TODO: support proxy per network. - } - // Whether a particular NetworkRequest listen should cause signal strength thresholds to // be communicated to a particular NetworkAgent depends only on the network's immutable, // capabilities, so it only needs to be done once on initial connect, not every time the @@ -5905,10 +5930,16 @@ public class ConnectivityService extends IConnectivityManager.Stub } else if (state == NetworkInfo.State.DISCONNECTED) { networkAgent.asyncChannel.disconnect(); if (networkAgent.isVPN()) { - mProxyTracker.setDefaultProxyEnabled(true); updateUids(networkAgent, networkAgent.networkCapabilities, null); } disconnectAndDestroyNetwork(networkAgent); + if (networkAgent.isVPN()) { + // As the active or bound network changes for apps, broadcast the default proxy, as + // apps may need to update their proxy data. This is called after disconnecting from + // VPN to make sure we do not broadcast the old proxy data. + // TODO(b/122649188): send the broadcast only to VPN users. + mProxyTracker.sendProxyBroadcast(); + } } else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) || state == NetworkInfo.State.SUSPENDED) { // going into or coming out of SUSPEND: re-score and notify diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java index fdddccd207..a671287324 100644 --- a/services/core/java/com/android/server/connectivity/ProxyTracker.java +++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java @@ -309,22 +309,4 @@ public class ProxyTracker { } } } - - /** - * Enable or disable the default proxy. - * - * This sets the flag for enabling/disabling the default proxy and sends the broadcast - * if applicable. - * @param enabled whether the default proxy should be enabled. - */ - public void setDefaultProxyEnabled(final boolean enabled) { - synchronized (mProxyLock) { - if (mDefaultProxyEnabled != enabled) { - mDefaultProxyEnabled = enabled; - if (mGlobalProxy == null && mDefaultProxy != null) { - sendProxyBroadcast(); - } - } - } - } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index bf3964416e..ebca152176 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -121,6 +121,7 @@ import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkUtils; +import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.StringNetworkSpecifier; import android.net.UidRange; @@ -158,6 +159,7 @@ import com.android.server.connectivity.DefaultNetworkMetrics; import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.Nat464Xlat; +import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.net.NetworkPinner; @@ -1001,6 +1003,11 @@ public class ConnectivityServiceTest { return mock(Tethering.class); } + @Override + protected ProxyTracker makeProxyTracker() { + return mock(ProxyTracker.class); + } + @Override protected int reserveNetId() { while (true) { @@ -1023,6 +1030,11 @@ public class ConnectivityServiceTest { } } + @Override + protected boolean queryUserAccess(int uid, int netId) { + return true; + } + public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) { return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd; } @@ -4823,4 +4835,84 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(lp); verifyTcpBufferSizeChange(TEST_TCP_BUFFER_SIZES); } + + @Test + public void testGetGlobalProxyForNetwork() { + final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + final Network wifiNetwork = mWiFiNetworkAgent.getNetwork(); + when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo); + assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork)); + } + + @Test + public void testGetProxyForActiveNetwork() { + final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + waitForIdle(); + assertNull(mService.getProxyForNetwork(null)); + + final LinkProperties testLinkProperties = new LinkProperties(); + testLinkProperties.setHttpProxy(testProxyInfo); + + mWiFiNetworkAgent.sendLinkProperties(testLinkProperties); + waitForIdle(); + + assertEquals(testProxyInfo, mService.getProxyForNetwork(null)); + } + + @Test + public void testGetProxyForVPN() { + final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888); + + // Set up a WiFi network with no proxy + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + waitForIdle(); + assertNull(mService.getProxyForNetwork(null)); + + // Set up a VPN network with a proxy + final int uid = Process.myUid(); + final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + mMockVpn.setUids(ranges); + 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(); + + // Test that the VPN network returns a proxy, and the WiFi does not. + assertEquals(testProxyInfo, mService.getProxyForNetwork(vpnNetworkAgent.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); + waitForIdle(); + assertNull(mService.getProxyForNetwork(vpnNetworkAgent.getNetwork())); + assertNull(mService.getProxyForNetwork(null)); + + // Set WiFi proxy and check that the vpn proxy is still null. + testLinkProperties.setHttpProxy(testProxyInfo); + mWiFiNetworkAgent.sendLinkProperties(testLinkProperties); + waitForIdle(); + assertNull(mService.getProxyForNetwork(null)); + + // Disconnect from VPN and check that the active network, which is now the WiFi, has the + // correct proxy setting. + vpnNetworkAgent.disconnect(); + waitForIdle(); + assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork())); + assertEquals(testProxyInfo, mService.getProxyForNetwork(null)); + } } From b432c2c45cf2b9d39e67ddcbc4de6da344b1ecb8 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 24 Jan 2019 22:00:27 +0900 Subject: [PATCH 016/130] Add NetworkStack networking deps to SystemApi Test: atest FrameworksNetTests Bug: 112869080 Change-Id: Id59dc06fb85e4ac88098f56b621ec880610759ce --- .../android/net/StaticIpConfiguration.java | 66 ++++++++++++++++--- .../java/android/net/apf/ApfCapabilities.java | 5 ++ .../net/StaticIpConfigurationTest.java | 8 +-- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java index 3aa56b9025..25bae3c574 100644 --- a/core/java/android/net/StaticIpConfiguration.java +++ b/core/java/android/net/StaticIpConfiguration.java @@ -16,10 +16,11 @@ package android.net; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; -import android.net.LinkAddress; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; import java.net.InetAddress; import java.util.ArrayList; @@ -46,17 +47,22 @@ import java.util.Objects; * * @hide */ -public class StaticIpConfiguration implements Parcelable { +@SystemApi +@TestApi +public final class StaticIpConfiguration implements Parcelable { + /** @hide */ @UnsupportedAppUsage public LinkAddress ipAddress; + /** @hide */ @UnsupportedAppUsage public InetAddress gateway; + /** @hide */ @UnsupportedAppUsage public final ArrayList dnsServers; + /** @hide */ @UnsupportedAppUsage public String domains; - @UnsupportedAppUsage public StaticIpConfiguration() { dnsServers = new ArrayList(); } @@ -79,6 +85,41 @@ public class StaticIpConfiguration implements Parcelable { domains = null; } + public LinkAddress getIpAddress() { + return ipAddress; + } + + public void setIpAddress(LinkAddress ipAddress) { + this.ipAddress = ipAddress; + } + + public InetAddress getGateway() { + return gateway; + } + + public void setGateway(InetAddress gateway) { + this.gateway = gateway; + } + + public List getDnsServers() { + return dnsServers; + } + + public String getDomains() { + return domains; + } + + public void setDomains(String newDomains) { + domains = newDomains; + } + + /** + * Add a DNS server to this configuration. + */ + public void addDnsServer(InetAddress server) { + dnsServers.add(server); + } + /** * Returns the network routes specified by this object. Will typically include a * directly-connected route for the IP address's local subnet and a default route. If the @@ -86,7 +127,6 @@ public class StaticIpConfiguration implements Parcelable { * route to the gateway as well. This configuration is arguably invalid, but it used to work * in K and earlier, and other OSes appear to accept it. */ - @UnsupportedAppUsage public List getRoutes(String iface) { List routes = new ArrayList(3); if (ipAddress != null) { @@ -107,6 +147,7 @@ public class StaticIpConfiguration implements Parcelable { * contained in the LinkProperties will not be a complete picture of the link's configuration, * because any configuration information that is obtained dynamically by the network (e.g., * IPv6 configuration) will not be included. + * @hide */ public LinkProperties toLinkProperties(String iface) { LinkProperties lp = new LinkProperties(); @@ -124,6 +165,7 @@ public class StaticIpConfiguration implements Parcelable { return lp; } + @Override public String toString() { StringBuffer str = new StringBuffer(); @@ -143,6 +185,7 @@ public class StaticIpConfiguration implements Parcelable { return str.toString(); } + @Override public int hashCode() { int result = 13; result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode()); @@ -168,12 +211,10 @@ public class StaticIpConfiguration implements Parcelable { } /** Implement the Parcelable interface */ - public static Creator CREATOR = + public static final Creator CREATOR = new Creator() { public StaticIpConfiguration createFromParcel(Parcel in) { - StaticIpConfiguration s = new StaticIpConfiguration(); - readFromParcel(s, in); - return s; + return readFromParcel(in); } public StaticIpConfiguration[] newArray(int size) { @@ -182,11 +223,13 @@ public class StaticIpConfiguration implements Parcelable { }; /** Implement the Parcelable interface */ + @Override public int describeContents() { return 0; } /** Implement the Parcelable interface */ + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(ipAddress, flags); NetworkUtils.parcelInetAddress(dest, gateway, flags); @@ -197,7 +240,9 @@ public class StaticIpConfiguration implements Parcelable { dest.writeString(domains); } - protected static void readFromParcel(StaticIpConfiguration s, Parcel in) { + /** @hide */ + public static StaticIpConfiguration readFromParcel(Parcel in) { + final StaticIpConfiguration s = new StaticIpConfiguration(); s.ipAddress = in.readParcelable(null); s.gateway = NetworkUtils.unparcelInetAddress(in); s.dnsServers.clear(); @@ -206,5 +251,6 @@ public class StaticIpConfiguration implements Parcelable { s.dnsServers.add(NetworkUtils.unparcelInetAddress(in)); } s.domains = in.readString(); + return s; } } diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java index f28cdc9028..73cf94b785 100644 --- a/core/java/android/net/apf/ApfCapabilities.java +++ b/core/java/android/net/apf/ApfCapabilities.java @@ -16,11 +16,16 @@ package android.net.apf; +import android.annotation.SystemApi; +import android.annotation.TestApi; + /** * APF program support capabilities. * * @hide */ +@SystemApi +@TestApi public class ApfCapabilities { /** * Version of APF instruction set supported for packet filtering. 0 indicates no support for diff --git a/tests/net/java/android/net/StaticIpConfigurationTest.java b/tests/net/java/android/net/StaticIpConfigurationTest.java index 5bb5734553..2b5ad378e0 100644 --- a/tests/net/java/android/net/StaticIpConfigurationTest.java +++ b/tests/net/java/android/net/StaticIpConfigurationTest.java @@ -26,13 +26,13 @@ import android.os.Parcel; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.net.InetAddress; import java.util.HashSet; import java.util.Objects; -import org.junit.Test; -import org.junit.runner.RunWith; - @RunWith(AndroidJUnit4.class) @SmallTest public class StaticIpConfigurationTest { @@ -203,7 +203,7 @@ public class StaticIpConfigurationTest { try { s.writeToParcel(p, 0); p.setDataPosition(0); - s2 = StaticIpConfiguration.CREATOR.createFromParcel(p); + s2 = StaticIpConfiguration.readFromParcel(p); } finally { p.recycle(); } From 98d9df7a9bb7c14be546324203d4812fe33a365f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 25 Jan 2019 08:54:08 +0900 Subject: [PATCH 017/130] Move NetworkUtils used by NetworkStack Depending on usage move into NetworkStackUtils or shared Inet4AddressUtils. Test: atest FrameworksNetTests NetworkStackTests Bug: 112869080 (Cherry-pick of aosp/881952) Change-Id: Ie20dcee375b377236004a7689890729493aca857 --- core/java/android/net/NetworkUtils.java | 156 ++------------- .../java/android/net/NetworkUtilsTest.java | 188 +----------------- 2 files changed, 23 insertions(+), 321 deletions(-) diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index c996d01fe8..39db4fef78 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -21,8 +21,10 @@ import static android.system.OsConstants.AF_INET6; import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; +import android.net.shared.Inet4AddressUtils; import android.os.Build; import android.os.Parcel; +import android.system.ErrnoException; import android.system.Os; import android.util.Log; import android.util.Pair; @@ -39,8 +41,6 @@ import java.util.Collection; import java.util.Locale; import java.util.TreeSet; -import android.system.ErrnoException; - /** * Native methods for managing network interfaces. * @@ -177,119 +177,37 @@ public class NetworkUtils { FileDescriptor fd) throws IOException; /** - * @see #intToInet4AddressHTL(int) - * @deprecated Use either {@link #intToInet4AddressHTH(int)} - * or {@link #intToInet4AddressHTL(int)} + * @see Inet4AddressUtils#intToInet4AddressHTL(int) + * @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)} + * or {@link Inet4AddressUtils#intToInet4AddressHTL(int)} */ @Deprecated @UnsupportedAppUsage public static InetAddress intToInetAddress(int hostAddress) { - return intToInet4AddressHTL(hostAddress); + return Inet4AddressUtils.intToInet4AddressHTL(hostAddress); } /** - * Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4) - * - *

This method uses the higher-order int bytes as the lower-order IPv4 address bytes, - * which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead. - * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is - * lower-order IPv4 address byte - */ - public static Inet4Address intToInet4AddressHTL(int hostAddress) { - return intToInet4AddressHTH(Integer.reverseBytes(hostAddress)); - } - - /** - * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4) - * @param hostAddress an int coding for an IPv4 address - */ - public static Inet4Address intToInet4AddressHTH(int hostAddress) { - byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)), - (byte) (0xff & (hostAddress >> 16)), - (byte) (0xff & (hostAddress >> 8)), - (byte) (0xff & hostAddress) }; - - try { - return (Inet4Address) InetAddress.getByAddress(addressBytes); - } catch (UnknownHostException e) { - throw new AssertionError(); - } - } - - /** - * @see #inet4AddressToIntHTL(Inet4Address) - * @deprecated Use either {@link #inet4AddressToIntHTH(Inet4Address)} - * or {@link #inet4AddressToIntHTL(Inet4Address)} + * @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address) + * @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)} + * or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)} */ @Deprecated public static int inetAddressToInt(Inet4Address inetAddr) throws IllegalArgumentException { - return inet4AddressToIntHTL(inetAddr); + return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr); } /** - * Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304) - * - *

This conversion can help order IP addresses: considering the ordering - * 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned - * integers with {@link Integer#toUnsignedLong}. - * @param inetAddr is an InetAddress corresponding to the IPv4 address - * @return the IP address as integer - */ - public static int inet4AddressToIntHTH(Inet4Address inetAddr) - throws IllegalArgumentException { - byte [] addr = inetAddr.getAddress(); - return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16) - | ((addr[2] & 0xff) << 8) | (addr[3] & 0xff); - } - - /** - * Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201) - * - *

This method stores the higher-order IPv4 address bytes in the lower-order int bytes, - * which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead. - * @param inetAddr is an InetAddress corresponding to the IPv4 address - * @return the IP address as integer - */ - public static int inet4AddressToIntHTL(Inet4Address inetAddr) { - return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr)); - } - - /** - * @see #prefixLengthToV4NetmaskIntHTL(int) - * @deprecated Use either {@link #prefixLengthToV4NetmaskIntHTH(int)} - * or {@link #prefixLengthToV4NetmaskIntHTL(int)} + * @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int) + * @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)} + * or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)} */ @Deprecated @UnsupportedAppUsage public static int prefixLengthToNetmaskInt(int prefixLength) throws IllegalArgumentException { - return prefixLengthToV4NetmaskIntHTL(prefixLength); - } - - /** - * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000) - * @return the IPv4 netmask as an integer - */ - public static int prefixLengthToV4NetmaskIntHTH(int prefixLength) - throws IllegalArgumentException { - if (prefixLength < 0 || prefixLength > 32) { - throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)"); - } - // (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1) - return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength); - } - - /** - * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff). - * - *

This method stores the higher-order IPv4 address bytes in the lower-order int bytes, - * which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead. - * @return the IPv4 netmask as an integer - */ - public static int prefixLengthToV4NetmaskIntHTL(int prefixLength) - throws IllegalArgumentException { - return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength)); + return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength); } /** @@ -307,17 +225,13 @@ public class NetworkUtils { * @return the network prefix length * @throws IllegalArgumentException the specified netmask was not contiguous. * @hide + * @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)} */ @UnsupportedAppUsage + @Deprecated public static int netmaskToPrefixLength(Inet4Address netmask) { - // inetAddressToInt returns an int in *network* byte order. - int i = Integer.reverseBytes(inetAddressToInt(netmask)); - int prefixLength = Integer.bitCount(i); - int trailingZeros = Integer.numberOfTrailingZeros(i); - if (trailingZeros != 32 - prefixLength) { - throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i)); - } - return prefixLength; + // This is only here because some apps seem to be using it (@UnsupportedAppUsage). + return Inet4AddressUtils.netmaskToPrefixLength(netmask); } @@ -408,16 +322,8 @@ public class NetworkUtils { */ @UnsupportedAppUsage public static int getImplicitNetmask(Inet4Address address) { - int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value. - if (firstByte < 128) { - return 8; - } else if (firstByte < 192) { - return 16; - } else if (firstByte < 224) { - return 24; - } else { - return 32; // Will likely not end well for other reasons. - } + // Only here because it seems to be used by apps + return Inet4AddressUtils.getImplicitNetmask(address); } /** @@ -444,28 +350,6 @@ public class NetworkUtils { return new Pair(address, prefixLength); } - /** - * Get a prefix mask as Inet4Address for a given prefix length. - * - *

For example 20 -> 255.255.240.0 - */ - public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength) - throws IllegalArgumentException { - return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength)); - } - - /** - * Get the broadcast address for a given prefix. - * - *

For example 192.168.0.1/24 -> 192.168.0.255 - */ - public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength) - throws IllegalArgumentException { - final int intBroadcastAddr = inet4AddressToIntHTH(addr) - | ~prefixLengthToV4NetmaskIntHTH(prefixLength); - return intToInet4AddressHTH(intBroadcastAddr); - } - /** * Check if IP address type is consistent between two InetAddress. * @return true if both are the same type. False otherwise. diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java index 3452819835..ba6e0f2990 100644 --- a/tests/net/java/android/net/NetworkUtilsTest.java +++ b/tests/net/java/android/net/NetworkUtilsTest.java @@ -16,161 +16,19 @@ package android.net; -import static android.net.NetworkUtils.getImplicitNetmask; -import static android.net.NetworkUtils.inet4AddressToIntHTH; -import static android.net.NetworkUtils.inet4AddressToIntHTL; -import static android.net.NetworkUtils.intToInet4AddressHTH; -import static android.net.NetworkUtils.intToInet4AddressHTL; -import static android.net.NetworkUtils.netmaskToPrefixLength; -import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH; -import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTL; -import static android.net.NetworkUtils.getBroadcastAddress; -import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; - import static junit.framework.Assert.assertEquals; -import static org.junit.Assert.fail; - import android.support.test.runner.AndroidJUnit4; -import java.math.BigInteger; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.util.TreeSet; - import org.junit.Test; import org.junit.runner.RunWith; +import java.math.BigInteger; +import java.util.TreeSet; + @RunWith(AndroidJUnit4.class) @android.support.test.filters.SmallTest public class NetworkUtilsTest { - - private InetAddress Address(String addr) { - return InetAddress.parseNumericAddress(addr); - } - - private Inet4Address IPv4Address(String addr) { - return (Inet4Address) Address(addr); - } - - @Test - public void testGetImplicitNetmask() { - assertEquals(8, getImplicitNetmask(IPv4Address("4.2.2.2"))); - assertEquals(8, getImplicitNetmask(IPv4Address("10.5.6.7"))); - assertEquals(16, getImplicitNetmask(IPv4Address("173.194.72.105"))); - assertEquals(16, getImplicitNetmask(IPv4Address("172.23.68.145"))); - assertEquals(24, getImplicitNetmask(IPv4Address("192.0.2.1"))); - assertEquals(24, getImplicitNetmask(IPv4Address("192.168.5.1"))); - assertEquals(32, getImplicitNetmask(IPv4Address("224.0.0.1"))); - assertEquals(32, getImplicitNetmask(IPv4Address("255.6.7.8"))); - } - - private void assertInvalidNetworkMask(Inet4Address addr) { - try { - netmaskToPrefixLength(addr); - fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception"); - } catch (IllegalArgumentException expected) { - } - } - - @Test - public void testInet4AddressToIntHTL() { - assertEquals(0, inet4AddressToIntHTL(IPv4Address("0.0.0.0"))); - assertEquals(0x000080ff, inet4AddressToIntHTL(IPv4Address("255.128.0.0"))); - assertEquals(0x0080ff0a, inet4AddressToIntHTL(IPv4Address("10.255.128.0"))); - assertEquals(0x00feff0a, inet4AddressToIntHTL(IPv4Address("10.255.254.0"))); - assertEquals(0xfeffa8c0, inet4AddressToIntHTL(IPv4Address("192.168.255.254"))); - assertEquals(0xffffa8c0, inet4AddressToIntHTL(IPv4Address("192.168.255.255"))); - } - - @Test - public void testIntToInet4AddressHTL() { - assertEquals(IPv4Address("0.0.0.0"), intToInet4AddressHTL(0)); - assertEquals(IPv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff)); - assertEquals(IPv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a)); - assertEquals(IPv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a)); - assertEquals(IPv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0)); - assertEquals(IPv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0)); - } - - @Test - public void testInet4AddressToIntHTH() { - assertEquals(0, inet4AddressToIntHTH(IPv4Address("0.0.0.0"))); - assertEquals(0xff800000, inet4AddressToIntHTH(IPv4Address("255.128.0.0"))); - assertEquals(0x0aff8000, inet4AddressToIntHTH(IPv4Address("10.255.128.0"))); - assertEquals(0x0afffe00, inet4AddressToIntHTH(IPv4Address("10.255.254.0"))); - assertEquals(0xc0a8fffe, inet4AddressToIntHTH(IPv4Address("192.168.255.254"))); - assertEquals(0xc0a8ffff, inet4AddressToIntHTH(IPv4Address("192.168.255.255"))); - } - - @Test - public void testIntToInet4AddressHTH() { - assertEquals(IPv4Address("0.0.0.0"), intToInet4AddressHTH(0)); - assertEquals(IPv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000)); - assertEquals(IPv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000)); - assertEquals(IPv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00)); - assertEquals(IPv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe)); - assertEquals(IPv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff)); - } - - @Test - public void testNetmaskToPrefixLength() { - assertEquals(0, netmaskToPrefixLength(IPv4Address("0.0.0.0"))); - assertEquals(9, netmaskToPrefixLength(IPv4Address("255.128.0.0"))); - assertEquals(17, netmaskToPrefixLength(IPv4Address("255.255.128.0"))); - assertEquals(23, netmaskToPrefixLength(IPv4Address("255.255.254.0"))); - assertEquals(31, netmaskToPrefixLength(IPv4Address("255.255.255.254"))); - assertEquals(32, netmaskToPrefixLength(IPv4Address("255.255.255.255"))); - - assertInvalidNetworkMask(IPv4Address("0.0.0.1")); - assertInvalidNetworkMask(IPv4Address("255.255.255.253")); - assertInvalidNetworkMask(IPv4Address("255.255.0.255")); - } - - @Test - public void testPrefixLengthToV4NetmaskIntHTL() { - assertEquals(0, prefixLengthToV4NetmaskIntHTL(0)); - assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9)); - assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17)); - assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23)); - assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31)); - assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32)); - } - - @Test - public void testPrefixLengthToV4NetmaskIntHTH() { - assertEquals(0, prefixLengthToV4NetmaskIntHTH(0)); - assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9)); - assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17)); - assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23)); - assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31)); - assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32)); - } - - @Test(expected = IllegalArgumentException.class) - public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() { - prefixLengthToV4NetmaskIntHTH(-1); - } - - @Test(expected = IllegalArgumentException.class) - public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() { - prefixLengthToV4NetmaskIntHTH(33); - } - - private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) { - final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength); - final int addrInt = inet4AddressToIntHTH(IPv4Address(addr)); - assertEquals(IPv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt)); - } - - @Test - public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() { - checkAddressMasking("192.168.0.0", "192.168.128.1", 16); - checkAddressMasking("255.240.0.0", "255.255.255.255", 12); - checkAddressMasking("255.255.255.255", "255.255.255.255", 32); - checkAddressMasking("0.0.0.0", "255.255.255.255", 0); - } - @Test public void testRoutedIPv4AddressCount() { final TreeSet set = new TreeSet<>(IpPrefix.lengthComparator()); @@ -267,44 +125,4 @@ public class NetworkUtilsTest { assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536), NetworkUtils.routedIPv6AddressCount(set)); } - - @Test - public void testGetPrefixMaskAsAddress() { - assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress()); - assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress()); - assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress()); - assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress()); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetPrefixMaskAsAddress_PrefixTooLarge() { - getPrefixMaskAsInet4Address(33); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetPrefixMaskAsAddress_NegativePrefix() { - getPrefixMaskAsInet4Address(-1); - } - - @Test - public void testGetBroadcastAddress() { - assertEquals("192.168.15.255", - getBroadcastAddress(IPv4Address("192.168.0.123"), 20).getHostAddress()); - assertEquals("192.255.255.255", - getBroadcastAddress(IPv4Address("192.168.0.123"), 8).getHostAddress()); - assertEquals("192.168.0.123", - getBroadcastAddress(IPv4Address("192.168.0.123"), 32).getHostAddress()); - assertEquals("255.255.255.255", - getBroadcastAddress(IPv4Address("192.168.0.123"), 0).getHostAddress()); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetBroadcastAddress_PrefixTooLarge() { - getBroadcastAddress(IPv4Address("192.168.0.123"), 33); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetBroadcastAddress_NegativePrefix() { - getBroadcastAddress(IPv4Address("192.168.0.123"), -1); - } } From 768ea1206dceec304c2dfdb41a8f06c58facb028 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 2 May 2018 21:14:54 +0900 Subject: [PATCH 018/130] Tell the factory it is already serving a request. This is a cherry-pick of ag/607226 that has been rebased on top of four years of changes and with comments addressed. Gives each factory a serial number and propogates it to every NetworkAgent so when a score comes back indicating a request is being handled the factory can account for it properly. Without this, a new request that's already handled by a network offered by a factory will not cause an increment of the factorys ref count. Concretely this results in issues like the RAT icon not being displayed in spite of the network actually being up and usable. This will be ported to AOSP as soon as possible, but immediately some master-only WiFi tests need to be adjusted with this change which would not let me submit to AOSP. Bug: 18637384 Bug: 29030667 Test: manual Test: atest frameworks/opt/telephony/tests/telephonytests Test: atest frameworks-net Test: atest CtsNetTestCases CtsHostsideNetworkTests Change-Id: I597ac588f76dd507512ff02868fd1310b7e63f7e --- .../java/android/net/ConnectivityManager.java | 24 +++- .../android/net/IConnectivityManager.aidl | 4 +- core/java/android/net/NetworkAgent.java | 23 +++- .../android/server/ConnectivityService.java | 76 +++++++++-- .../server/connectivity/NetworkAgentInfo.java | 5 +- .../server/ConnectivityServiceTest.java | 122 +++++++++++------- .../connectivity/LingerMonitorTest.java | 4 +- 7 files changed, 185 insertions(+), 73 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3bae12e937..ef8ca9e3cb 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -2918,11 +2918,11 @@ public class ConnectivityManager { } } - /** {@hide} */ + /** {@hide} - returns the factory serial number */ @UnsupportedAppUsage - public void registerNetworkFactory(Messenger messenger, String name) { + public int registerNetworkFactory(Messenger messenger, String name) { try { - mService.registerNetworkFactory(messenger, name); + return mService.registerNetworkFactory(messenger, name); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -2938,6 +2938,10 @@ public class ConnectivityManager { } } + // TODO : remove this method. It is a stopgap measure to help sheperding a number + // of dependent changes that would conflict throughout the automerger graph. Having this + // temporarily helps with the process of going through with all these dependent changes across + // the entire tree. /** * @hide * Register a NetworkAgent with ConnectivityService. @@ -2945,8 +2949,20 @@ public class ConnectivityManager { */ public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkMisc misc) { + return registerNetworkAgent(messenger, ni, lp, nc, score, misc, + NetworkFactory.SerialNumber.NONE); + } + + /** + * @hide + * Register a NetworkAgent with ConnectivityService. + * @return NetID corresponding to NetworkAgent. + */ + public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + NetworkCapabilities nc, int score, NetworkMisc misc, int factorySerialNumber) { try { - return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc); + return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc, + factorySerialNumber); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index fd7360fd4c..f88adc2c64 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -139,14 +139,14 @@ interface IConnectivityManager void setAirplaneMode(boolean enable); - void registerNetworkFactory(in Messenger messenger, in String name); + int registerNetworkFactory(in Messenger messenger, in String name); boolean requestBandwidthUpdate(in Network network); void unregisterNetworkFactory(in Messenger messenger); int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, - in NetworkCapabilities nc, int score, in NetworkMisc misc); + in NetworkCapabilities nc, int score, in NetworkMisc misc, in int factorySerialNumber); NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, in Messenger messenger, int timeoutSec, in IBinder binder, int legacy); diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 99bfc140f1..204c25f01d 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -58,6 +58,7 @@ public abstract class NetworkAgent extends Handler { private static final long BW_REFRESH_MIN_WIN_MS = 500; private boolean mPollLceScheduled = false; private AtomicBoolean mPollLcePending = new AtomicBoolean(false); + public final int mFactorySerialNumber; private static final int BASE = Protocol.BASE_NETWORK_AGENT; @@ -193,16 +194,31 @@ public abstract class NetworkAgent extends Handler { */ public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15; + // TODO : remove these two constructors. They are a stopgap measure to help sheperding a number + // of dependent changes that would conflict throughout the automerger graph. Having these + // temporarily helps with the process of going through with all these dependent changes across + // the entire tree. public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score) { - this(looper, context, logTag, ni, nc, lp, score, null); + this(looper, context, logTag, ni, nc, lp, score, null, NetworkFactory.SerialNumber.NONE); + } + public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, + NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) { + this(looper, context, logTag, ni, nc, lp, score, misc, NetworkFactory.SerialNumber.NONE); } public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, - NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) { + NetworkCapabilities nc, LinkProperties lp, int score, int factorySerialNumber) { + this(looper, context, logTag, ni, nc, lp, score, null, factorySerialNumber); + } + + public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, + NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc, + int factorySerialNumber) { super(looper); LOG_TAG = logTag; mContext = context; + mFactorySerialNumber = factorySerialNumber; if (ni == null || nc == null || lp == null) { throw new IllegalArgumentException(); } @@ -211,7 +227,8 @@ public abstract class NetworkAgent extends Handler { ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE); netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), - new LinkProperties(lp), new NetworkCapabilities(nc), score, misc); + new LinkProperties(lp), new NetworkCapabilities(nc), score, misc, + factorySerialNumber); } @Override diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index c8e5d2bdb7..de7c8cc7a6 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -79,6 +79,7 @@ import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.NetworkConfig; +import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; @@ -2773,8 +2774,17 @@ public class ConnectivityService extends IConnectivityManager.Stub for (NetworkRequestInfo nri : mNetworkRequests.values()) { if (nri.request.isListen()) continue; NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId); - ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, - (nai != null ? nai.getCurrentScore() : 0), 0, nri.request); + final int score; + final int serial; + if (nai != null) { + score = nai.getCurrentScore(); + serial = nai.factorySerialNumber; + } else { + score = 0; + serial = NetworkFactory.SerialNumber.NONE; + } + ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, serial, + nri.request); } } else { loge("Error connecting NetworkFactory"); @@ -2871,7 +2881,7 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId); if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) { clearNetworkForRequest(request.requestId); - sendUpdatedScoreToFactories(request, 0); + sendUpdatedScoreToFactories(request, null); } } nai.clearLingerState(); @@ -2947,7 +2957,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } rematchAllNetworksAndRequests(null, 0); if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) { - sendUpdatedScoreToFactories(nri.request, 0); + sendUpdatedScoreToFactories(nri.request, null); } } @@ -4532,11 +4542,14 @@ public class ConnectivityService extends IConnectivityManager.Stub public final String name; public final Messenger messenger; public final AsyncChannel asyncChannel; + public final int factorySerialNumber; - public NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel) { + NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel, + int factorySerialNumber) { this.name = name; this.messenger = messenger; this.asyncChannel = asyncChannel; + this.factorySerialNumber = factorySerialNumber; } } @@ -4897,10 +4910,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public void registerNetworkFactory(Messenger messenger, String name) { + public int registerNetworkFactory(Messenger messenger, String name) { enforceConnectivityInternalPermission(); - NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel()); + NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(), + NetworkFactory.SerialNumber.nextSerialNumber()); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi)); + return nfi.factorySerialNumber; } private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) { @@ -4992,9 +5007,35 @@ public class ConnectivityService extends IConnectivityManager.Stub return nri.request.requestId == mDefaultRequest.requestId; } + // TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent + // changes that would conflict throughout the automerger graph. Having this method temporarily + // helps with the process of going through with all these dependent changes across the entire + // tree. public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkMisc networkMisc) { + return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities, + currentScore, networkMisc, NetworkFactory.SerialNumber.NONE); + } + + /** + * Register a new agent with ConnectivityService to handle a network. + * + * @param messenger a messenger for ConnectivityService to contact the agent asynchronously. + * @param networkInfo the initial info associated with this network. It can be updated later : + * see {@link #updateNetworkInfo}. + * @param linkProperties the initial link properties of this network. They can be updated + * later : see {@link #updateLinkProperties}. + * @param networkCapabilities the initial capabilites of this network. They can be updated + * later : see {@link #updateNetworkCapabilities}. + * @param currentScore the initial score of the network. See + * {@link NetworkAgentInfo#getCurrentScore}. + * @param networkMisc metadata about the network. This is never updated. + * @param factorySerialNumber the serial number of the factory owning this NetworkAgent. + */ + public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + LinkProperties linkProperties, NetworkCapabilities networkCapabilities, + int currentScore, NetworkMisc networkMisc, int factorySerialNumber) { enforceConnectivityInternalPermission(); LinkProperties lp = new LinkProperties(linkProperties); @@ -5004,7 +5045,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore, - mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS); + mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS, + factorySerialNumber); // Make sure the network capabilities reflect what the agent info says. nai.networkCapabilities = mixInCapabilities(nai, nc); final String extraInfo = networkInfo.getExtraInfo(); @@ -5420,17 +5462,23 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkRequest nr = nai.requestAt(i); // Don't send listening requests to factories. b/17393458 if (nr.isListen()) continue; - sendUpdatedScoreToFactories(nr, nai.getCurrentScore()); + sendUpdatedScoreToFactories(nr, nai); } } - private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) { + private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, NetworkAgentInfo nai) { + int score = 0; + int serial = 0; + if (nai != null) { + score = nai.getCurrentScore(); + serial = nai.factorySerialNumber; + } if (VDBG || DDBG){ log("sending new Min Network Score(" + score + "): " + networkRequest.toString()); } for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, - networkRequest); + nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, + serial, networkRequest); } } @@ -5706,7 +5754,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO - this could get expensive if we have a lot of requests for this // network. Think about if there is a way to reduce this. Push // netid->request mapping to each factory? - sendUpdatedScoreToFactories(nri.request, score); + sendUpdatedScoreToFactories(nri.request, newNetwork); if (isDefaultRequest(nri)) { isNewDefault = true; oldDefaultNetwork = currentNetwork; @@ -5730,7 +5778,7 @@ public class ConnectivityService extends IConnectivityManager.Stub newNetwork.removeRequest(nri.request.requestId); if (currentNetwork == newNetwork) { clearNetworkForRequest(nri.request.requestId); - sendUpdatedScoreToFactories(nri.request, 0); + sendUpdatedScoreToFactories(nri.request, null); } else { Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " + newNetwork.name() + diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index d0cff25dbf..cd4ce2d142 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -235,6 +235,8 @@ public class NetworkAgentInfo implements Comparable { public final Messenger messenger; public final AsyncChannel asyncChannel; + public final int factorySerialNumber; + // Used by ConnectivityService to keep track of 464xlat. public Nat464Xlat clatd; @@ -252,7 +254,7 @@ public class NetworkAgentInfo implements Comparable { public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info, LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler, NetworkMisc misc, ConnectivityService connService, INetd netd, - INetworkManagementService nms) { + INetworkManagementService nms, int factorySerialNumber) { this.messenger = messenger; asyncChannel = ac; network = net; @@ -266,6 +268,7 @@ public class NetworkAgentInfo implements Comparable { mContext = context; mHandler = handler; networkMisc = misc; + this.factorySerialNumber = factorySerialNumber; } /** diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 036c5dcc89..3127d745b5 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -495,7 +495,7 @@ public class ConnectivityServiceTest { mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext, "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities, - linkProperties, mScore, new NetworkMisc()) { + linkProperties, mScore, new NetworkMisc(), NetworkFactory.SerialNumber.NONE) { @Override public void unwanted() { mDisconnected.open(); } @@ -725,7 +725,7 @@ public class ConnectivityServiceTest { /** * A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove * operations have been processed. Before ConnectivityService can add or remove any requests, - * the factory must be told to expect those operations by calling expectAddRequests or + * the factory must be told to expect those operations by calling expectAddRequestsWithScores or * expectRemoveRequests. */ private static class MockNetworkFactory extends NetworkFactory { @@ -734,19 +734,22 @@ public class ConnectivityServiceTest { private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false); // Used to expect that requests be removed or added on a separate thread, without sleeping. - // Callers can call either expectAddRequests() or expectRemoveRequests() exactly once, then - // cause some other thread to add or remove requests, then call waitForRequests(). We can - // either expect requests to be added or removed, but not both, because CountDownLatch can - // only count in one direction. - private CountDownLatch mExpectations; + // Callers can call either expectAddRequestsWithScores() or expectRemoveRequests() exactly + // once, then cause some other thread to add or remove requests, then call + // waitForRequests(). + // It is not possible to wait for both add and remove requests. When adding, the queue + // contains the expected score. When removing, the value is unused, all matters is the + // number of objects in the queue. + private final LinkedBlockingQueue mExpectations; // Whether we are currently expecting requests to be added or removed. Valid only if - // mExpectations is non-null. + // mExpectations is non-empty. private boolean mExpectingAdditions; public MockNetworkFactory(Looper looper, Context context, String logTag, NetworkCapabilities filter) { super(looper, context, logTag, filter); + mExpectations = new LinkedBlockingQueue<>(); } public int getMyRequestCount() { @@ -778,69 +781,82 @@ public class ConnectivityServiceTest { } @Override - protected void handleAddRequest(NetworkRequest request, int score) { - // If we're expecting anything, we must be expecting additions. - if (mExpectations != null && !mExpectingAdditions) { - fail("Can't add requests while expecting requests to be removed"); - } + protected void handleAddRequest(NetworkRequest request, int score, + int factorySerialNumber) { + synchronized (mExpectations) { + final Integer expectedScore = mExpectations.poll(); // null if the queue is empty - // Add the request. - super.handleAddRequest(request, score); + assertNotNull("Added more requests than expected (" + request + " score : " + + score + ")", expectedScore); + // If we're expecting anything, we must be expecting additions. + if (!mExpectingAdditions) { + fail("Can't add requests while expecting requests to be removed"); + } + if (expectedScore != score) { + fail("Expected score was " + expectedScore + " but actual was " + score + + " in added request"); + } - // Reduce the number of request additions we're waiting for. - if (mExpectingAdditions) { - assertTrue("Added more requests than expected", mExpectations.getCount() > 0); - mExpectations.countDown(); + // Add the request. + super.handleAddRequest(request, score, factorySerialNumber); + mExpectations.notify(); } } @Override protected void handleRemoveRequest(NetworkRequest request) { - // If we're expecting anything, we must be expecting removals. - if (mExpectations != null && mExpectingAdditions) { - fail("Can't remove requests while expecting requests to be added"); - } + synchronized (mExpectations) { + final Integer expectedScore = mExpectations.poll(); // null if the queue is empty - // Remove the request. - super.handleRemoveRequest(request); + assertTrue("Removed more requests than expected", expectedScore != null); + // If we're expecting anything, we must be expecting removals. + if (mExpectingAdditions) { + fail("Can't remove requests while expecting requests to be added"); + } - // Reduce the number of request removals we're waiting for. - if (!mExpectingAdditions) { - assertTrue("Removed more requests than expected", mExpectations.getCount() > 0); - mExpectations.countDown(); + // Remove the request. + super.handleRemoveRequest(request); + mExpectations.notify(); } } private void assertNoExpectations() { - if (mExpectations != null) { - fail("Can't add expectation, " + mExpectations.getCount() + " already pending"); + if (mExpectations.size() != 0) { + fail("Can't add expectation, " + mExpectations.size() + " already pending"); } } - // Expects that count requests will be added. - public void expectAddRequests(final int count) { + // Expects that requests with the specified scores will be added. + public void expectAddRequestsWithScores(final int... scores) { assertNoExpectations(); mExpectingAdditions = true; - mExpectations = new CountDownLatch(count); + for (int score : scores) { + mExpectations.add(score); + } } // Expects that count requests will be removed. public void expectRemoveRequests(final int count) { assertNoExpectations(); mExpectingAdditions = false; - mExpectations = new CountDownLatch(count); + for (int i = 0; i < count; ++i) { + mExpectations.add(0); // For removals the score is ignored so any value will do. + } } // Waits for the expected request additions or removals to happen within a timeout. public void waitForRequests() throws InterruptedException { - assertNotNull("Nothing to wait for", mExpectations); - mExpectations.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); - final long count = mExpectations.getCount(); + final long deadline = SystemClock.elapsedRealtime() + TIMEOUT_MS; + synchronized (mExpectations) { + while (mExpectations.size() > 0 && SystemClock.elapsedRealtime() < deadline) { + mExpectations.wait(deadline - SystemClock.elapsedRealtime()); + } + } + final long count = mExpectations.size(); final String msg = count + " requests still not " + (mExpectingAdditions ? "added" : "removed") + " after " + TIMEOUT_MS + " ms"; assertEquals(msg, 0, count); - mExpectations = null; } public void waitForNetworkRequests(final int count) throws InterruptedException { @@ -2271,6 +2287,12 @@ public class ConnectivityServiceTest { callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent); } + private int[] makeIntArray(final int size, final int value) { + final int[] array = new int[size]; + Arrays.fill(array, value); + return array; + } + private void tryNetworkFactoryRequests(int capability) throws Exception { // Verify NOT_RESTRICTED is set appropriately final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability) @@ -2292,7 +2314,7 @@ public class ConnectivityServiceTest { mServiceContext, "testFactory", filter); testFactory.setScoreFilter(40); ConditionVariable cv = testFactory.getNetworkStartedCV(); - testFactory.expectAddRequests(1); + testFactory.expectAddRequestsWithScores(0); testFactory.register(); testFactory.waitForNetworkRequests(1); int expectedRequestCount = 1; @@ -2303,7 +2325,7 @@ public class ConnectivityServiceTest { assertFalse(testFactory.getMyStartRequested()); NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build(); networkCallback = new NetworkCallback(); - testFactory.expectAddRequests(1); + testFactory.expectAddRequestsWithScores(0); // New request mCm.requestNetwork(request, networkCallback); expectedRequestCount++; testFactory.waitForNetworkRequests(expectedRequestCount); @@ -2323,7 +2345,7 @@ public class ConnectivityServiceTest { // When testAgent connects, ConnectivityService will re-send us all current requests with // the new score. There are expectedRequestCount such requests, and we must wait for all of // them. - testFactory.expectAddRequests(expectedRequestCount); + testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 50)); testAgent.connect(false); testAgent.addCapability(capability); waitFor(cv); @@ -2331,7 +2353,7 @@ public class ConnectivityServiceTest { assertFalse(testFactory.getMyStartRequested()); // Bring in a bunch of requests. - testFactory.expectAddRequests(10); + testFactory.expectAddRequestsWithScores(makeIntArray(10, 50)); assertEquals(expectedRequestCount, testFactory.getMyRequestCount()); ConnectivityManager.NetworkCallback[] networkCallbacks = new ConnectivityManager.NetworkCallback[10]; @@ -2354,8 +2376,11 @@ public class ConnectivityServiceTest { // Drop the higher scored network. cv = testFactory.getNetworkStartedCV(); + // With the default network disconnecting, the requests are sent with score 0 to factories. + testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 0)); testAgent.disconnect(); waitFor(cv); + testFactory.waitForNetworkRequests(expectedRequestCount); assertEquals(expectedRequestCount, testFactory.getMyRequestCount()); assertTrue(testFactory.getMyStartRequested()); @@ -3177,22 +3202,23 @@ public class ConnectivityServiceTest { testFactory.setScoreFilter(40); // Register the factory and expect it to start looking for a network. - testFactory.expectAddRequests(1); + testFactory.expectAddRequestsWithScores(0); // Score 0 as the request is not served yet. testFactory.register(); testFactory.waitForNetworkRequests(1); assertTrue(testFactory.getMyStartRequested()); // Bring up wifi. The factory stops looking for a network. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - testFactory.expectAddRequests(2); // Because the default request changes score twice. + // Score 60 - 40 penalty for not validated yet, then 60 when it validates + testFactory.expectAddRequestsWithScores(20, 60); mWiFiNetworkAgent.connect(true); - testFactory.waitForNetworkRequests(1); + testFactory.waitForRequests(); assertFalse(testFactory.getMyStartRequested()); ContentResolver cr = mServiceContext.getContentResolver(); // Turn on mobile data always on. The factory starts looking again. - testFactory.expectAddRequests(1); + testFactory.expectAddRequestsWithScores(0); // Always on requests comes up with score 0 setAlwaysOnNetworks(true); testFactory.waitForNetworkRequests(2); assertTrue(testFactory.getMyStartRequested()); @@ -3200,7 +3226,7 @@ public class ConnectivityServiceTest { // Bring up cell data and check that the factory stops looking. assertLength(1, mCm.getAllNetworks()); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); - testFactory.expectAddRequests(2); // Because the cell request changes score twice. + testFactory.expectAddRequestsWithScores(10, 50); // Unvalidated, then validated mCellNetworkAgent.connect(true); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); testFactory.waitForNetworkRequests(2); diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index 9578ded1a0..e877a8f7e6 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -35,6 +35,7 @@ import android.net.ConnectivityManager; import android.net.INetd; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkMisc; import android.net.NetworkStack; @@ -356,7 +357,8 @@ public class LingerMonitorTest { caps.addCapability(0); caps.addTransportType(transport); NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null, - caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS); + caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS, + NetworkFactory.SerialNumber.NONE); nai.everValidated = true; return nai; } From 6bd9193a3d3c0de163b8cd47e2bde875ca1a3861 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 30 Jan 2019 22:01:20 +0900 Subject: [PATCH 019/130] Add SystemApi for captive portal metrics The metrics go through NetworkMonitor in the NetworkStack so that they can be upgraded to new metrics in the future. Test: flashed, captive portal login works, metrics shown in events log Bug: 112869080 (Cherry-pick of aosp/890004) Change-Id: I4bccfbd87bae5b2d65e45c7a5918aa45ab5d76e8 --- core/java/android/net/CaptivePortal.java | 13 +++++++++++++ .../com/android/server/ConnectivityService.java | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java index 3b01266737..3ab35e1eeb 100644 --- a/core/java/android/net/CaptivePortal.java +++ b/core/java/android/net/CaptivePortal.java @@ -117,4 +117,17 @@ public class CaptivePortal implements Parcelable { } catch (RemoteException e) { } } + + /** + * Log a captive portal login event. + * @hide + */ + @SystemApi + @TestApi + public void logEvent(int eventId, String packageName) { + try { + ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName); + } catch (RemoteException e) { + } + } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1519c17850..a5cdf37e58 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -144,6 +144,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; +import com.android.internal.logging.MetricsLogger; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnInfo; @@ -2683,6 +2684,11 @@ public class ConnectivityService extends IConnectivityManager.Stub EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE, mNai.network.netId)); } + + @Override + public void logCaptivePortalLoginEvent(int eventId, String packageName) { + new MetricsLogger().action(eventId, packageName); + } } private boolean networkRequiresValidation(NetworkAgentInfo nai) { From 1fb0c95661e8a827571a7266a62f1fbaa27cf032 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 3 Jan 2019 18:50:15 +0800 Subject: [PATCH 020/130] [KA02] internal cleanup and refactor for SocketKeepalive In previous change, the new SocketKeepalive API was exported. But internally, old PacketKeepalive names and structures are still used. This change rename them properly for code consistency and also refactor KeepalivePacketData to support different types of KeepalivePacketData. (clean cherry-pick from aosp/860394) Bug: 114151147 Test: 1. atest FrameworksNetTests 2. atest FrameworksWifiTests 3. atest FrameworksTelephonyTests Change-Id: Ia9917d12987e91e87e34ffb3f126e7bc7c9c187e --- .../java/android/net/ConnectivityManager.java | 2 +- .../java/android/net/KeepalivePacketData.java | 57 ++------------ .../android/net/NattKeepalivePacketData.java | 77 +++++++++++++++++++ core/java/android/net/NetworkAgent.java | 37 +++++---- core/java/android/net/SocketKeepalive.java | 14 +++- .../android/server/ConnectivityService.java | 17 ++-- .../server/connectivity/KeepaliveTracker.java | 62 ++++++++------- .../server/ConnectivityServiceTest.java | 29 ++++--- 8 files changed, 176 insertions(+), 119 deletions(-) create mode 100644 core/java/android/net/NattKeepalivePacketData.java diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1656c6f8a1..ce2de9ac63 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1816,7 +1816,7 @@ public class ConnectivityManager { @Override public void handleMessage(Message message) { switch (message.what) { - case NetworkAgent.EVENT_PACKET_KEEPALIVE: + case NetworkAgent.EVENT_SOCKET_KEEPALIVE: int error = message.arg2; try { if (error == SUCCESS) { diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java index 7436ad0878..16555d8bd4 100644 --- a/core/java/android/net/KeepalivePacketData.java +++ b/core/java/android/net/KeepalivePacketData.java @@ -16,22 +16,20 @@ package android.net; -import static android.net.ConnectivityManager.PacketKeepalive.*; +import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; +import static android.net.SocketKeepalive.ERROR_INVALID_PORT; +import android.net.SocketKeepalive.InvalidPacketException; import android.net.util.IpUtils; import android.os.Parcel; import android.os.Parcelable; -import android.system.OsConstants; import android.util.Log; -import java.net.Inet4Address; import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; /** * Represents the actual packets that are sent by the - * {@link android.net.ConnectivityManager.PacketKeepalive} API. + * {@link android.net.SocketKeepalive} API. * * @hide */ @@ -53,8 +51,8 @@ public class KeepalivePacketData implements Parcelable { /** Packet data. A raw byte string of packet data, not including the link-layer header. */ private final byte[] mPacket; - private static final int IPV4_HEADER_LENGTH = 20; - private static final int UDP_HEADER_LENGTH = 8; + protected static final int IPV4_HEADER_LENGTH = 20; + protected static final int UDP_HEADER_LENGTH = 8; // This should only be constructed via static factory methods, such as // nattKeepalivePacket @@ -80,53 +78,10 @@ public class KeepalivePacketData implements Parcelable { } } - public static class InvalidPacketException extends Exception { - public final int error; - public InvalidPacketException(int error) { - this.error = error; - } - } - public byte[] getPacket() { return mPacket.clone(); } - public static KeepalivePacketData nattKeepalivePacket( - InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort) - throws InvalidPacketException { - - if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) { - throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); - } - - if (dstPort != NATT_PORT) { - throw new InvalidPacketException(ERROR_INVALID_PORT); - } - - int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1; - ByteBuffer buf = ByteBuffer.allocate(length); - buf.order(ByteOrder.BIG_ENDIAN); - buf.putShort((short) 0x4500); // IP version and TOS - buf.putShort((short) length); - buf.putInt(0); // ID, flags, offset - buf.put((byte) 64); // TTL - buf.put((byte) OsConstants.IPPROTO_UDP); - int ipChecksumOffset = buf.position(); - buf.putShort((short) 0); // IP checksum - buf.put(srcAddress.getAddress()); - buf.put(dstAddress.getAddress()); - buf.putShort((short) srcPort); - buf.putShort((short) dstPort); - buf.putShort((short) (length - 20)); // UDP length - int udpChecksumOffset = buf.position(); - buf.putShort((short) 0); // UDP checksum - buf.put((byte) 0xff); // NAT-T keepalive - buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0)); - buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH)); - - return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array()); - } - /* Parcelable Implementation */ public int describeContents() { return 0; diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java new file mode 100644 index 0000000000..aa9f799c6f --- /dev/null +++ b/core/java/android/net/NattKeepalivePacketData.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 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.net.SocketKeepalive.InvalidPacketException; +import android.net.util.IpUtils; +import android.system.OsConstants; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** @hide */ +public final class NattKeepalivePacketData extends KeepalivePacketData { + + // This should only be constructed via static factory methods, such as + // nattKeepalivePacket + private NattKeepalivePacketData(InetAddress srcAddress, int srcPort, + InetAddress dstAddress, int dstPort, byte[] data) throws + InvalidPacketException { + super(srcAddress, srcPort, dstAddress, dstPort, data); + } + + /** + * Factory method to create Nat-T keepalive packet structure. + */ + public static NattKeepalivePacketData nattKeepalivePacket( + InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort) + throws InvalidPacketException { + + if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) { + throw new InvalidPacketException(SocketKeepalive.ERROR_INVALID_IP_ADDRESS); + } + + if (dstPort != NattSocketKeepalive.NATT_PORT) { + throw new InvalidPacketException(SocketKeepalive.ERROR_INVALID_PORT); + } + + int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1; + ByteBuffer buf = ByteBuffer.allocate(length); + buf.order(ByteOrder.BIG_ENDIAN); + buf.putShort((short) 0x4500); // IP version and TOS + buf.putShort((short) length); + buf.putInt(0); // ID, flags, offset + buf.put((byte) 64); // TTL + buf.put((byte) OsConstants.IPPROTO_UDP); + int ipChecksumOffset = buf.position(); + buf.putShort((short) 0); // IP checksum + buf.put(srcAddress.getAddress()); + buf.put(dstAddress.getAddress()); + buf.putShort((short) srcPort); + buf.putShort((short) dstPort); + buf.putShort((short) (length - 20)); // UDP length + int udpChecksumOffset = buf.position(); + buf.putShort((short) 0); // UDP checksum + buf.put((byte) 0xff); // NAT-T keepalive + buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0)); + buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH)); + + return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array()); + } +} diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 204c25f01d..c37837837a 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -18,7 +18,6 @@ package android.net; import android.annotation.UnsupportedAppUsage; import android.content.Context; -import android.net.ConnectivityManager.PacketKeepalive; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -155,7 +154,7 @@ public abstract class NetworkAgent extends Handler { * * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. */ - public static final int CMD_START_PACKET_KEEPALIVE = BASE + 11; + public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11; /** * Requests that the specified keepalive packet be stopped. @@ -164,20 +163,20 @@ public abstract class NetworkAgent extends Handler { * * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. */ - public static final int CMD_STOP_PACKET_KEEPALIVE = BASE + 12; + public static final int CMD_STOP_SOCKET_KEEPALIVE = BASE + 12; /** - * Sent by the NetworkAgent to ConnectivityService to provide status on a packet keepalive - * request. This may either be the reply to a CMD_START_PACKET_KEEPALIVE, or an asynchronous + * Sent by the NetworkAgent to ConnectivityService to provide status on a socket keepalive + * request. This may either be the reply to a CMD_START_SOCKET_KEEPALIVE, or an asynchronous * error notification. * - * This is also sent by KeepaliveTracker to the app's ConnectivityManager.PacketKeepalive to - * so that the app's PacketKeepaliveCallback methods can be called. + * This is also sent by KeepaliveTracker to the app's {@link SocketKeepalive}, + * so that the app's {@link SocketKeepalive.Callback} methods can be called. * * arg1 = slot number of the keepalive * arg2 = error code */ - public static final int EVENT_PACKET_KEEPALIVE = BASE + 13; + public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13; /** * Sent by ConnectivityService to inform this network transport of signal strength thresholds @@ -305,12 +304,12 @@ public abstract class NetworkAgent extends Handler { saveAcceptUnvalidated(msg.arg1 != 0); break; } - case CMD_START_PACKET_KEEPALIVE: { - startPacketKeepalive(msg); + case CMD_START_SOCKET_KEEPALIVE: { + startSocketKeepalive(msg); break; } - case CMD_STOP_PACKET_KEEPALIVE: { - stopPacketKeepalive(msg); + case CMD_STOP_SOCKET_KEEPALIVE: { + stopSocketKeepalive(msg); break; } @@ -460,22 +459,22 @@ public abstract class NetworkAgent extends Handler { /** * Requests that the network hardware send the specified packet at the specified interval. */ - protected void startPacketKeepalive(Message msg) { - onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED); + protected void startSocketKeepalive(Message msg) { + onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED); } /** * Requests that the network hardware send the specified packet at the specified interval. */ - protected void stopPacketKeepalive(Message msg) { - onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED); + protected void stopSocketKeepalive(Message msg) { + onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED); } /** - * Called by the network when a packet keepalive event occurs. + * Called by the network when a socket keepalive event occurs. */ - public void onPacketKeepaliveEvent(int slot, int reason) { - queueOrSendMessage(EVENT_PACKET_KEEPALIVE, slot, reason); + public void onSocketKeepaliveEvent(int slot, int reason) { + queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, reason); } /** diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java index 97d50f4bac..a47c11af40 100644 --- a/core/java/android/net/SocketKeepalive.java +++ b/core/java/android/net/SocketKeepalive.java @@ -109,6 +109,18 @@ public abstract class SocketKeepalive implements AutoCloseable { **/ public static final int MAX_INTERVAL_SEC = 3600; + /** + * This packet is invalid. + * See the error code for details. + * @hide + */ + public static class InvalidPacketException extends Exception { + public final int error; + public InvalidPacketException(int error) { + this.error = error; + } + } + @NonNull final IConnectivityManager mService; @NonNull final Network mNetwork; @NonNull private final Executor mExecutor; @@ -135,7 +147,7 @@ public abstract class SocketKeepalive implements AutoCloseable { @Override public void handleMessage(Message message) { switch (message.what) { - case NetworkAgent.EVENT_PACKET_KEEPALIVE: + case NetworkAgent.EVENT_SOCKET_KEEPALIVE: final int status = message.arg2; try { if (status == SUCCESS) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f807543808..1cb2c4a2f5 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -60,7 +60,6 @@ import android.content.res.Configuration; import android.database.ContentObserver; import android.net.ConnectionInfo; import android.net.ConnectivityManager; -import android.net.ConnectivityManager.PacketKeepalive; import android.net.IConnectivityManager; import android.net.IIpConnectivityMetrics; import android.net.INetd; @@ -94,6 +93,7 @@ import android.net.NetworkWatchlistManager; import android.net.PrivateDnsConfigParcel; import android.net.ProxyInfo; import android.net.RouteInfo; +import android.net.SocketKeepalive; import android.net.UidRange; import android.net.Uri; import android.net.VpnService; @@ -2488,8 +2488,8 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.networkMisc.acceptUnvalidated = msg.arg1 == 1; break; } - case NetworkAgent.EVENT_PACKET_KEEPALIVE: { - mKeepaliveTracker.handleEventPacketKeepalive(nai, msg); + case NetworkAgent.EVENT_SOCKET_KEEPALIVE: { + mKeepaliveTracker.handleEventSocketKeepalive(nai, msg); break; } } @@ -2863,8 +2863,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // sending all CALLBACK_LOST messages (for requests, not listens) at the end // of rematchAllNetworksAndRequests notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST); - mKeepaliveTracker.handleStopAllKeepalives(nai, - ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK); + mKeepaliveTracker.handleStopAllKeepalives(nai, SocketKeepalive.ERROR_INVALID_NETWORK); for (String iface : nai.linkProperties.getAllInterfaceNames()) { // Disable wakeup packet monitoring for each interface. wakeupModifyInterface(iface, nai.networkCapabilities, false); @@ -3456,12 +3455,12 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } // Sent by KeepaliveTracker to process an app request on the state machine thread. - case NetworkAgent.CMD_START_PACKET_KEEPALIVE: { + case NetworkAgent.CMD_START_SOCKET_KEEPALIVE: { mKeepaliveTracker.handleStartKeepalive(msg); break; } // Sent by KeepaliveTracker to process an app request on the state machine thread. - case NetworkAgent.CMD_STOP_PACKET_KEEPALIVE: { + case NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE: { NetworkAgentInfo nai = getNetworkAgentInfoForNetwork((Network) msg.obj); int slot = msg.arg1; int reason = msg.arg2; @@ -6363,7 +6362,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mKeepaliveTracker.startNattKeepalive( getNetworkAgentInfoForNetwork(network), intervalSeconds, messenger, binder, - srcAddr, srcPort, dstAddr, ConnectivityManager.PacketKeepalive.NATT_PORT); + srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT); } @Override @@ -6380,7 +6379,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void stopKeepalive(Network network, int slot) { mHandler.sendMessage(mHandler.obtainMessage( - NetworkAgent.CMD_STOP_PACKET_KEEPALIVE, slot, PacketKeepalive.SUCCESS, network)); + NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE, slot, SocketKeepalive.SUCCESS, network)); } @Override diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 1559ba8ba8..07e28f9fb5 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -16,26 +16,27 @@ package com.android.server.connectivity; -// TODO: Clean up imports and remove references of PacketKeepalive constants. - -import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_INTERVAL; -import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS; -import static android.net.ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK; -import static android.net.ConnectivityManager.PacketKeepalive.MIN_INTERVAL; -import static android.net.ConnectivityManager.PacketKeepalive.NATT_PORT; -import static android.net.ConnectivityManager.PacketKeepalive.NO_KEEPALIVE; -import static android.net.ConnectivityManager.PacketKeepalive.SUCCESS; -import static android.net.NetworkAgent.CMD_START_PACKET_KEEPALIVE; -import static android.net.NetworkAgent.CMD_STOP_PACKET_KEEPALIVE; -import static android.net.NetworkAgent.EVENT_PACKET_KEEPALIVE; +import static android.net.NattSocketKeepalive.NATT_PORT; +import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE; +import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE; +import static android.net.NetworkAgent.EVENT_SOCKET_KEEPALIVE; +import static android.net.SocketKeepalive.BINDER_DIED; +import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL; +import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; +import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK; import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET; +import static android.net.SocketKeepalive.MAX_INTERVAL_SEC; +import static android.net.SocketKeepalive.MIN_INTERVAL_SEC; +import static android.net.SocketKeepalive.NO_KEEPALIVE; +import static android.net.SocketKeepalive.SUCCESS; import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.ConnectivityManager.PacketKeepalive; import android.net.KeepalivePacketData; +import android.net.NattKeepalivePacketData; import android.net.NetworkAgent; import android.net.NetworkUtils; +import android.net.SocketKeepalive.InvalidPacketException; import android.net.util.IpUtils; import android.os.Binder; import android.os.Handler; @@ -60,7 +61,7 @@ import java.util.ArrayList; import java.util.HashMap; /** - * Manages packet keepalive requests. + * Manages socket keepalive requests. * * Provides methods to stop and start keepalive requests, and keeps track of keepalives across all * networks. This class is tightly coupled to ConnectivityService. It is not thread-safe and its @@ -83,13 +84,13 @@ public class KeepaliveTracker { } /** - * Tracks information about a packet keepalive. + * Tracks information about a socket keepalive. * * All information about this keepalive is known at construction time except the slot number, * which is only returned when the hardware has successfully started the keepalive. */ class KeepaliveInfo implements IBinder.DeathRecipient { - // Bookkeping data. + // Bookkeeping data. private final Messenger mMessenger; private final IBinder mBinder; private final int mUid; @@ -98,7 +99,7 @@ public class KeepaliveTracker { /** Keepalive slot. A small integer that identifies this keepalive among the ones handled * by this network. */ - private int mSlot = PacketKeepalive.NO_KEEPALIVE; + private int mSlot = NO_KEEPALIVE; // Packet data. private final KeepalivePacketData mPacket; @@ -144,7 +145,7 @@ public class KeepaliveTracker { .toString(); } - /** Sends a message back to the application via its PacketKeepalive.Callback. */ + /** Sends a message back to the application via its SocketKeepalive.Callback. */ void notifyMessenger(int slot, int err) { KeepaliveTracker.this.notifyMessenger(mMessenger, slot, err); } @@ -153,8 +154,8 @@ public class KeepaliveTracker { public void binderDied() { // Not called from ConnectivityService handler thread, so send it a message. mConnectivityServiceHandler.obtainMessage( - NetworkAgent.CMD_STOP_PACKET_KEEPALIVE, - mSlot, PacketKeepalive.BINDER_DIED, mNai.network).sendToTarget(); + NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE, + mSlot, BINDER_DIED, mNai.network).sendToTarget(); } void unlinkDeathRecipient() { @@ -181,7 +182,10 @@ public class KeepaliveTracker { } private int checkInterval() { - return mInterval >= MIN_INTERVAL ? SUCCESS : ERROR_INVALID_INTERVAL; + if (mInterval < MIN_INTERVAL_SEC || mInterval > MAX_INTERVAL_SEC) { + return ERROR_INVALID_INTERVAL; + } + return SUCCESS; } private int isValid() { @@ -198,7 +202,7 @@ public class KeepaliveTracker { int error = isValid(); if (error == SUCCESS) { Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name()); - mNai.asyncChannel.sendMessage(CMD_START_PACKET_KEEPALIVE, slot, mInterval, mPacket); + mNai.asyncChannel.sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket); } else { handleStopKeepalive(mNai, mSlot, error); return; @@ -214,7 +218,7 @@ public class KeepaliveTracker { } if (isStarted) { Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name()); - mNai.asyncChannel.sendMessage(CMD_STOP_PACKET_KEEPALIVE, mSlot); + mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); } // TODO: at the moment we unconditionally return failure here. In cases where the // NetworkAgent is alive, should we ask it to reply, so it can return failure? @@ -225,7 +229,7 @@ public class KeepaliveTracker { void notifyMessenger(Messenger messenger, int slot, int err) { Message message = Message.obtain(); - message.what = EVENT_PACKET_KEEPALIVE; + message.what = EVENT_SOCKET_KEEPALIVE; message.arg1 = slot; message.arg2 = err; message.obj = null; @@ -310,7 +314,7 @@ public class KeepaliveTracker { } /** Handle keepalive events from lower layer. */ - public void handleEventPacketKeepalive(@NonNull NetworkAgentInfo nai, + public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, @NonNull Message message) { int slot = message.arg1; int reason = message.arg2; @@ -369,16 +373,16 @@ public class KeepaliveTracker { KeepalivePacketData packet; try { - packet = KeepalivePacketData.nattKeepalivePacket( + packet = NattKeepalivePacketData.nattKeepalivePacket( srcAddress, srcPort, dstAddress, NATT_PORT); - } catch (KeepalivePacketData.InvalidPacketException e) { + } catch (InvalidPacketException e) { notifyMessenger(messenger, NO_KEEPALIVE, e.error); return; } KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds); Log.d(TAG, "Created keepalive: " + ki.toString()); mConnectivityServiceHandler.obtainMessage( - NetworkAgent.CMD_START_PACKET_KEEPALIVE, ki).sendToTarget(); + CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget(); } /** @@ -432,7 +436,7 @@ public class KeepaliveTracker { } public void dump(IndentingPrintWriter pw) { - pw.println("Packet keepalives:"); + pw.println("Socket keepalives:"); pw.increaseIndent(); for (NetworkAgentInfo nai : mKeepalives.keySet()) { pw.println(nai.name()); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 50468cbe70..e2d59d6485 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -194,6 +194,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -500,17 +501,17 @@ public class ConnectivityServiceTest { public void unwanted() { mDisconnected.open(); } @Override - public void startPacketKeepalive(Message msg) { + public void startSocketKeepalive(Message msg) { int slot = msg.arg1; if (mExpectedKeepaliveSlot != null) { assertEquals((int) mExpectedKeepaliveSlot, slot); } - onPacketKeepaliveEvent(slot, mStartKeepaliveError); + onSocketKeepaliveEvent(slot, mStartKeepaliveError); } @Override - public void stopPacketKeepalive(Message msg) { - onPacketKeepaliveEvent(msg.arg1, mStopKeepaliveError); + public void stopSocketKeepalive(Message msg) { + onSocketKeepaliveEvent(msg.arg1, mStopKeepaliveError); } @Override @@ -3817,10 +3818,17 @@ public class ConnectivityServiceTest { @Test public void testNattSocketKeepalives() throws Exception { + final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor(); + doTestNattSocketKeepalivesWithExecutor(executorSingleThread); + executorSingleThread.shutdown(); + + final Executor executorInline = (Runnable r) -> r.run(); + doTestNattSocketKeepalivesWithExecutor(executorInline); + } + + private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception { // TODO: 1. Move this outside of ConnectivityServiceTest. - // 2. Add helper function to test against newSingleThreadExecutor as well as inline - // executor. - // 3. Make test to verify that Nat-T keepalive socket is created by IpSecService. + // 2. Make test to verify that Nat-T keepalive socket is created by IpSecService. final int srcPort = 12345; final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129"); final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35"); @@ -3834,8 +3842,6 @@ public class ConnectivityServiceTest { final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(srcPort); - final Executor executor = Executors.newSingleThreadExecutor(); - LinkProperties lp = new LinkProperties(); lp.setInterfaceName("wlan12"); lp.addLinkAddress(new LinkAddress(myIPv6, 64)); @@ -3952,6 +3958,11 @@ public class ConnectivityServiceTest { ka2.stop(); callback2.expectStopped(); + + testSocket.close(); + testSocket2.close(); + + mWiFiNetworkAgent.disconnect(); } @Test From 4ad1b9f839770af4208112431aa52bbcfaa361de Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Tue, 8 Jan 2019 12:09:18 -0800 Subject: [PATCH 021/130] [CS] Support "instant failure" from factories Add a mechanism by which a factory can declare "instant failure" for a request - which would result in it getting an OnUnavailable() (even without a timeout). Factories may only do this iff: 1. They know they are the only factory which may fulfill this request (common for transport-specific requests). 2. The know that the request can definitely not be fulfilled at any point in the future. Bug: 31382922 Test: atest ConnectivityServiceTest Change-Id: I9bce0f4d85fa8cad7f8a9998819f945b778c5ac5 --- .../java/android/net/ConnectivityManager.java | 6 +- .../android/server/ConnectivityService.java | 40 +++++++++--- .../server/ConnectivityServiceTest.java | 65 ++++++++++++++++++- 3 files changed, 99 insertions(+), 12 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2aca55aacf..34311cb4ff 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -3138,9 +3138,9 @@ public class ConnectivityManager { /** * Called if no network is found in the timeout time specified in - * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call. This callback is not - * called for the version of {@link #requestNetwork(NetworkRequest, NetworkCallback)} - * without timeout. When this callback is invoked the associated + * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call or if the + * requested network request cannot be fulfilled (whether or not a timeout was + * specified). When this callback is invoked the associated * {@link NetworkRequest} will have already been removed and released, as if * {@link #unregisterNetworkCallback(NetworkCallback)} had been called. */ diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d1cd072ee2..e78322b0ab 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1048,7 +1048,8 @@ public class ConnectivityService extends IConnectivityManager.Stub handleRegisterNetworkRequest(new NetworkRequestInfo( null, networkRequest, new Binder())); } else { - handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID); + handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID, + /* callOnUnavailable */ false); } } @@ -2629,11 +2630,25 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; } + private boolean maybeHandleNetworkFactoryMessage(Message msg) { + switch (msg.what) { + default: + return false; + case NetworkFactory.EVENT_UNFULFILLABLE_REQUEST: { + handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.sendingUid, + /* callOnUnavailable */ true); + break; + } + } + return true; + } + @Override public void handleMessage(Message msg) { - if (!maybeHandleAsyncChannelMessage(msg) && - !maybeHandleNetworkMonitorMessage(msg) && - !maybeHandleNetworkAgentInfoMessage(msg)) { + if (!maybeHandleAsyncChannelMessage(msg) + && !maybeHandleNetworkMonitorMessage(msg) + && !maybeHandleNetworkAgentInfoMessage(msg) + && !maybeHandleNetworkFactoryMessage(msg)) { maybeHandleNetworkAgentMessage(msg); } } @@ -2780,6 +2795,9 @@ public class ConnectivityService extends IConnectivityManager.Stub if (mNetworkFactoryInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (VDBG) log("NetworkFactory connected"); + // Finish setting up the full connection + mNetworkFactoryInfos.get(msg.replyTo).asyncChannel.sendMessage( + AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); // A network factory has connected. Send it all current NetworkRequests. for (NetworkRequestInfo nri : mNetworkRequests.values()) { if (nri.request.isListen()) continue; @@ -2948,7 +2966,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (existingRequest != null) { // remove the existing request. if (DBG) log("Replacing " + existingRequest.request + " with " + nri.request + " because their intents matched."); - handleReleaseNetworkRequest(existingRequest.request, getCallingUid()); + handleReleaseNetworkRequest(existingRequest.request, getCallingUid(), + /* callOnUnavailable */ false); } handleRegisterNetworkRequest(nri); } @@ -2974,7 +2993,7 @@ public class ConnectivityService extends IConnectivityManager.Stub int callingUid) { NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent); if (nri != null) { - handleReleaseNetworkRequest(nri.request, callingUid); + handleReleaseNetworkRequest(nri.request, callingUid, /* callOnUnavailable */ false); } } @@ -3057,7 +3076,8 @@ public class ConnectivityService extends IConnectivityManager.Stub callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0); } - private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) { + private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid, + boolean callOnUnavailable) { final NetworkRequestInfo nri = getNriForAppRequest(request, callingUid, "release NetworkRequest"); if (nri == null) { @@ -3067,6 +3087,9 @@ public class ConnectivityService extends IConnectivityManager.Stub log("releasing " + nri.request + " (release request)"); } handleRemoveNetworkRequest(nri); + if (callOnUnavailable) { + callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0); + } } private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) { @@ -3457,7 +3480,8 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case EVENT_RELEASE_NETWORK_REQUEST: { - handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1); + handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1, + /* callOnUnavailable */ false); break; } case EVENT_SET_ACCEPT_UNVALIDATED: { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index a7c95c78d0..65e8314321 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -153,6 +153,7 @@ import android.test.mock.MockContentResolver; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import android.util.SparseArray; import com.android.internal.net.VpnConfig; import com.android.internal.util.ArrayUtils; @@ -747,6 +748,10 @@ public class ConnectivityServiceTest { // mExpectations is non-empty. private boolean mExpectingAdditions; + // Used to collect the networks requests managed by this factory. This is a duplicate of + // the internal information stored in the NetworkFactory (which is private). + private SparseArray mNetworkRequests = new SparseArray<>(); + public MockNetworkFactory(Looper looper, Context context, String logTag, NetworkCapabilities filter) { super(looper, context, logTag, filter); @@ -799,6 +804,7 @@ public class ConnectivityServiceTest { } // Add the request. + mNetworkRequests.put(request.requestId, request); super.handleAddRequest(request, score, factorySerialNumber); mExpectations.notify(); } @@ -816,11 +822,17 @@ public class ConnectivityServiceTest { } // Remove the request. + mNetworkRequests.remove(request.requestId); super.handleRemoveRequest(request); mExpectations.notify(); } } + // Trigger releasing the request as unfulfillable + public void triggerUnfulfillable(NetworkRequest r) { + super.releaseRequestAsUnfulfillableByAnyFactory(r); + } + private void assertNoExpectations() { if (mExpectations.size() != 0) { fail("Can't add expectation, " + mExpectations.size() + " already pending"); @@ -860,9 +872,11 @@ public class ConnectivityServiceTest { assertEquals(msg, 0, count); } - public void waitForNetworkRequests(final int count) throws InterruptedException { + public SparseArray waitForNetworkRequests(final int count) + throws InterruptedException { waitForRequests(); assertEquals(count, getMyRequestCount()); + return mNetworkRequests; } } @@ -3523,6 +3537,55 @@ public class ConnectivityServiceTest { networkCallback.assertNoCallback(); } + /** + * Validate the callback flow for a factory releasing a request as unfulfillable. + */ + @Test + public void testUnfulfillableNetworkRequest() throws Exception { + NetworkRequest nr = new NetworkRequest.Builder().addTransportType( + NetworkCapabilities.TRANSPORT_WIFI).build(); + final TestNetworkCallback networkCallback = new TestNetworkCallback(); + + final HandlerThread handlerThread = new HandlerThread("testUnfulfillableNetworkRequest"); + handlerThread.start(); + NetworkCapabilities filter = new NetworkCapabilities() + .addTransportType(TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET); + final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), + mServiceContext, "testFactory", filter); + testFactory.setScoreFilter(40); + + // Register the factory and expect it to receive the default request. + testFactory.expectAddRequestsWithScores(0); + testFactory.register(); + SparseArray requests = testFactory.waitForNetworkRequests(1); + + assertEquals(1, requests.size()); // have 1 request at this point + int origRequestId = requests.valueAt(0).requestId; + + // Now file the test request and expect it. + testFactory.expectAddRequestsWithScores(0); + mCm.requestNetwork(nr, networkCallback); + requests = testFactory.waitForNetworkRequests(2); // have 2 requests at this point + + int newRequestId = 0; + for (int i = 0; i < requests.size(); ++i) { + if (requests.valueAt(i).requestId != origRequestId) { + newRequestId = requests.valueAt(i).requestId; + break; + } + } + + // Simulate the factory releasing the request as unfulfillable and expect onUnavailable! + testFactory.expectRemoveRequests(1); + testFactory.triggerUnfulfillable(requests.get(newRequestId)); + networkCallback.expectCallback(CallbackState.UNAVAILABLE, null); + testFactory.waitForRequests(); + + testFactory.unregister(); + handlerThread.quit(); + } + private static class TestKeepaliveCallback extends PacketKeepaliveCallback { public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }; From ad9f6d89f6b6e52f4022ca9a979e5a239ab4f1b1 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 13 Feb 2019 20:58:59 +0900 Subject: [PATCH 022/130] Remove NetworkMonitor dependency on ICaptivePortal ICaptivePortal is used in the framework and cannot be used as a dependency in NetworkMonitor, as the framework class takes precedence when linking. Also fix NetworkMonitorTest that was not verifying the right startCaptivePortalApp call. (cherry-pick of aosp/904953 with minor conflict in Android.bp) Test: atest FrameworksNetTests NetworkStackTests Bug: 124033493 Change-Id: Ib6a89e54312628662b130fbeec18d11e139f09fa --- .../java/android/net/ConnectivityManager.java | 5 +- .../android/net/IConnectivityManager.aidl | 2 +- .../android/server/ConnectivityService.java | 50 ++++++++++++++++--- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2aca55aacf..c4b7957f3f 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -3927,15 +3927,16 @@ public class ConnectivityManager { * *

This endpoint is exclusively for use by the NetworkStack and is protected by the * corresponding permission. + * @param network Network on which the captive portal was detected. * @param appExtras Extras to include in the app start intent. * @hide */ @SystemApi @TestApi @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) - public void startCaptivePortalApp(Bundle appExtras) { + public void startCaptivePortalApp(Network network, Bundle appExtras) { try { - mService.startCaptivePortalAppInternal(appExtras); + mService.startCaptivePortalAppInternal(network, appExtras); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 872671fa56..87c62d2f10 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -168,7 +168,7 @@ interface IConnectivityManager void setAcceptUnvalidated(in Network network, boolean accept, boolean always); void setAvoidUnvalidated(in Network network); void startCaptivePortalApp(in Network network); - void startCaptivePortalAppInternal(in Bundle appExtras); + void startCaptivePortalAppInternal(in Network network, in Bundle appExtras); boolean getAvoidBadWifi(); int getMultipathPreference(in Network Network); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d1cd072ee2..e4c2dabada 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -57,8 +57,10 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.database.ContentObserver; +import android.net.CaptivePortal; import android.net.ConnectionInfo; import android.net.ConnectivityManager; +import android.net.ICaptivePortal; import android.net.IConnectivityManager; import android.net.IIpConnectivityMetrics; import android.net.INetd; @@ -2690,11 +2692,6 @@ public class ConnectivityService extends IConnectivityManager.Stub EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE, mNai.network.netId)); } - - @Override - public void logCaptivePortalLoginEvent(int eventId, String packageName) { - new MetricsLogger().action(eventId, packageName); - } } private boolean networkRequiresValidation(NetworkAgentInfo nai) { @@ -3247,22 +3244,63 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * NetworkStack endpoint to start the captive portal app. The NetworkStack needs to use this * endpoint as it does not have INTERACT_ACROSS_USERS_FULL itself. + * @param network Network on which the captive portal was detected. * @param appExtras Bundle to use as intent extras for the captive portal application. * Must be treated as opaque to avoid preventing the captive portal app to * update its arguments. */ @Override - public void startCaptivePortalAppInternal(Bundle appExtras) { + public void startCaptivePortalAppInternal(Network network, Bundle appExtras) { mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); final Intent appIntent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); appIntent.putExtras(appExtras); + appIntent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL, + new CaptivePortal(new CaptivePortalImpl(network).asBinder())); appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); Binder.withCleanCallingIdentity(() -> mContext.startActivityAsUser(appIntent, UserHandle.CURRENT)); } + private class CaptivePortalImpl extends ICaptivePortal.Stub { + private final Network mNetwork; + + private CaptivePortalImpl(Network network) { + mNetwork = network; + } + + @Override + public void appResponse(final int response) throws RemoteException { + if (response == CaptivePortal.APP_RETURN_WANTED_AS_IS) { + enforceSettingsPermission(); + } + + // getNetworkAgentInfoForNetwork is thread-safe + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(mNetwork); + if (nai == null) return; + + // nai.networkMonitor() is thread-safe + final INetworkMonitor nm = nai.networkMonitor(); + if (nm == null) return; + + final long token = Binder.clearCallingIdentity(); + try { + nm.notifyCaptivePortalAppFinished(response); + } finally { + // Not using Binder.withCleanCallingIdentity() to keep the checked RemoteException + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void logEvent(int eventId, String packageName) { + enforceSettingsPermission(); + + new MetricsLogger().action(eventId, packageName); + } + } + public boolean avoidBadWifi() { return mMultinetworkPolicyTracker.getAvoidBadWifi(); } From b6997cc4daa2cd93c788162caceaaca6d53850de Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 14 Feb 2019 18:04:20 +0900 Subject: [PATCH 023/130] Move NetworkStack to services.net NetworkStack is only used in services.net or clients of services.net. It cannot stay in framework.jar because it needs to depend on AIDL interfaces, which would conflict with app implementations if they were in framework.jar. (cherry-pick of aosp/905233 with trivial conflicts in SystemServer.java) Test: atest FrameworksNetTests NetworkStackTests Bug: 124033493 Change-Id: I501b125a388c1100c2182bde4670944c2f0d7a02 --- .../java/com/android/server/ConnectivityService.java | 8 +++++++- .../java/com/android/server/ConnectivityServiceTest.java | 9 +++++++-- .../android/server/connectivity/LingerMonitorTest.java | 5 ----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index e4c2dabada..2955a68145 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -88,6 +88,7 @@ import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; +import android.net.NetworkStackClient; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.NetworkWatchlistManager; @@ -5135,7 +5136,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (DBG) log("registerNetworkAgent " + nai); final long token = Binder.clearCallingIdentity(); try { - mContext.getSystemService(NetworkStack.class).makeNetworkMonitor( + getNetworkStack().makeNetworkMonitor( toStableParcelable(nai.network), name, new NetworkMonitorCallbacks(nai)); } finally { Binder.restoreCallingIdentity(token); @@ -5147,6 +5148,11 @@ public class ConnectivityService extends IConnectivityManager.Stub return nai.network.netId; } + @VisibleForTesting + protected NetworkStackClient getNetworkStack() { + return NetworkStackClient.getInstance(); + } + private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) { nai.onNetworkMonitorCreated(networkMonitor); if (VDBG) log("Got NetworkAgent Messenger"); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index a7c95c78d0..bfbcd6f88f 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -123,7 +123,7 @@ import android.net.NetworkMisc; import android.net.NetworkParcelable; import android.net.NetworkRequest; import android.net.NetworkSpecifier; -import android.net.NetworkStack; +import android.net.NetworkStackClient; import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.RouteInfo; @@ -245,7 +245,7 @@ public class ConnectivityServiceTest { @Mock INetworkStatsService mStatsService; @Mock INetworkPolicyManager mNpm; @Mock INetd mMockNetd; - @Mock NetworkStack mNetworkStack; + @Mock NetworkStackClient mNetworkStack; private ArgumentCaptor mStringArrayCaptor = ArgumentCaptor.forClass(String[].class); @@ -1076,6 +1076,11 @@ public class ConnectivityServiceTest { return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker; } + @Override + protected NetworkStackClient getNetworkStack() { + return mNetworkStack; + } + @Override public WakeupMessage makeWakeupMessage( Context context, Handler handler, String cmdName, int cmd, Object obj) { diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index e877a8f7e6..5057443eee 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -38,7 +38,6 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkMisc; -import android.net.NetworkStack; import android.os.INetworkManagementService; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -75,16 +74,12 @@ public class LingerMonitorTest { @Mock NetworkMisc mMisc; @Mock NetworkNotificationManager mNotifier; @Mock Resources mResources; - @Mock NetworkStack mNetworkStack; @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mCtx.getResources()).thenReturn(mResources); when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity"); - when(mCtx.getSystemServiceName(NetworkStack.class)) - .thenReturn(Context.NETWORK_STACK_SERVICE); - when(mCtx.getSystemService(Context.NETWORK_STACK_SERVICE)).thenReturn(mNetworkStack); mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT); } From bb27866cfbd9c7b771d03831008e0c2f53077fcb Mon Sep 17 00:00:00 2001 From: Andrei Onea Date: Mon, 25 Feb 2019 13:25:32 +0000 Subject: [PATCH 024/130] Add @UnsupportedAppUsage annotations For packages: android.net android.net.wifi android.nfc This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Change-Id: I7489aad1dceeb18ed7ca48a1ed8829a668b3fa04 --- core/java/android/net/IConnectivityManager.aidl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 87c62d2f10..bd2b4eb323 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -47,10 +47,12 @@ interface IConnectivityManager { Network getActiveNetwork(); Network getActiveNetworkForUid(int uid, boolean ignoreBlocked); + @UnsupportedAppUsage NetworkInfo getActiveNetworkInfo(); NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked); NetworkInfo getNetworkInfo(int networkType); NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked); + @UnsupportedAppUsage NetworkInfo[] getAllNetworkInfo(); Network getNetworkForType(int networkType); Network[] getAllNetworks(); @@ -58,12 +60,14 @@ interface IConnectivityManager boolean isNetworkSupported(int networkType); + @UnsupportedAppUsage LinkProperties getActiveLinkProperties(); LinkProperties getLinkPropertiesForType(int networkType); LinkProperties getLinkProperties(in Network network); NetworkCapabilities getNetworkCapabilities(in Network network); + @UnsupportedAppUsage NetworkState[] getAllNetworkState(); NetworkQuotaInfo getActiveNetworkQuotaInfo(); @@ -75,6 +79,7 @@ interface IConnectivityManager int untether(String iface, String callerPkg); + @UnsupportedAppUsage int getLastTetherError(String iface); boolean isTetheringSupported(String callerPkg); @@ -84,16 +89,21 @@ interface IConnectivityManager void stopTethering(int type, String callerPkg); + @UnsupportedAppUsage String[] getTetherableIfaces(); + @UnsupportedAppUsage String[] getTetheredIfaces(); + @UnsupportedAppUsage String[] getTetheringErroredIfaces(); String[] getTetheredDhcpRanges(); + @UnsupportedAppUsage String[] getTetherableUsbRegexs(); + @UnsupportedAppUsage String[] getTetherableWifiRegexs(); String[] getTetherableBluetoothRegexs(); @@ -118,6 +128,7 @@ interface IConnectivityManager VpnConfig getVpnConfig(int userId); + @UnsupportedAppUsage void startLegacyVpn(in VpnProfile profile); LegacyVpnInfo getLegacyVpnInfo(int userId); From 45406bff69ac269f1397e132deab4b1f791724e3 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Thu, 7 Feb 2019 14:13:13 -0800 Subject: [PATCH 025/130] Remove ConnectivityManager and its usages from NetworkStatsService. NSS needed it for getting VpnInfo[], NetworkState[] and activeLinkProperties which it used to query via ConnectivityManager. For VpnInfo[], this was racy as NSS may ignore intermediate changes to a VPN's underlying networks. See http://b/123961098 for more context. It may also lead to deadlocks b/w ConnectivityService and NetworkStatsService. See http://b/126245192 for more info. This change will ensure that NSS is never contending on any of ConnectivityService locks. Bug: 123961098 Bug: 126245192 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: I57e117bb4e9efe491b19d6b5a479f2d58d1c58e6 --- .../android/net/IConnectivityManager.aidl | 2 - .../android/server/ConnectivityService.java | 22 +++-- .../server/ConnectivityServiceTest.java | 63 ++++++++++++--- .../server/net/NetworkStatsServiceTest.java | 81 +++++++++---------- 4 files changed, 108 insertions(+), 60 deletions(-) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 87c62d2f10..7482e9de05 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -122,8 +122,6 @@ interface IConnectivityManager LegacyVpnInfo getLegacyVpnInfo(int userId); - VpnInfo[] getAllVpnInfo(); - boolean updateLockdownVpn(); boolean isAlwaysOnVpnPackageSupported(int userId, String packageName); boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown, diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ed459dbfc4..81a9ec5738 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4094,12 +4094,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * Return the information of all ongoing VPNs. This method is used by NetworkStatsService - * and not available in ConnectivityManager. + * Return the information of all ongoing VPNs. + * + *

This method is used to update NetworkStatsService. + * + *

Must be called on the handler thread. */ - @Override - public VpnInfo[] getAllVpnInfo() { - enforceConnectivityInternalPermission(); + private VpnInfo[] getAllVpnInfo() { + ensureRunningOnConnectivityServiceThread(); synchronized (mVpns) { if (mLockdownEnabled) { return new VpnInfo[0]; @@ -6434,6 +6436,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * Must be called on the handler thread. */ private Network[] getDefaultNetworks() { + ensureRunningOnConnectivityServiceThread(); ArrayList defaultNetworks = new ArrayList<>(); NetworkAgentInfo defaultNetwork = getDefaultNetwork(); for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { @@ -6449,8 +6452,15 @@ public class ConnectivityService extends IConnectivityManager.Stub * properties tracked by NetworkStatsService on an active iface has changed. */ private void notifyIfacesChangedForNetworkStats() { + ensureRunningOnConnectivityServiceThread(); + String activeIface = null; + LinkProperties activeLinkProperties = getActiveLinkProperties(); + if (activeLinkProperties != null) { + activeIface = activeLinkProperties.getInterfaceName(); + } try { - mStatsService.forceUpdateIfaces(getDefaultNetworks()); + mStatsService.forceUpdateIfaces( + getDefaultNetworks(), getAllVpnInfo(), getAllNetworkState(), activeIface); } catch (Exception ignored) { } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index ed524f61e3..d96c48df4e 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -125,6 +125,7 @@ import android.net.NetworkParcelable; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStackClient; +import android.net.NetworkState; import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.RouteInfo; @@ -157,6 +158,7 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.net.VpnConfig; +import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.test.BroadcastInterceptingContext; @@ -4356,48 +4358,91 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - Network[] onlyCell = new Network[]{mCellNetworkAgent.getNetwork()}; - Network[] onlyWifi = new Network[]{mWiFiNetworkAgent.getNetwork()}; + Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()}; + Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()}; + + LinkProperties cellLp = new LinkProperties(); + cellLp.setInterfaceName(MOBILE_IFNAME); + LinkProperties wifiLp = new LinkProperties(); + wifiLp.setInterfaceName(WIFI_IFNAME); // Simple connection should have updated ifaces mCellNetworkAgent.connect(false); + mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Default network switch should update ifaces. mWiFiNetworkAgent.connect(false); + mWiFiNetworkAgent.sendLinkProperties(wifiLp); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyWifi); + assertEquals(wifiLp, mService.getActiveLinkProperties()); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyWifi), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(WIFI_IFNAME)); reset(mStatsService); // Disconnect should update ifaces. mWiFiNetworkAgent.disconnect(); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Metered change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Captive portal change shouldn't update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); waitForIdle(); - verify(mStatsService, never()).forceUpdateIfaces(onlyCell); + verify(mStatsService, never()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Roaming change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); } diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index f89f303a13..d91d3eb10f 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -70,7 +70,6 @@ import android.app.usage.NetworkStatsManager; import android.content.Context; import android.content.Intent; import android.net.DataUsageRequest; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsSession; import android.net.LinkProperties; @@ -163,7 +162,6 @@ public class NetworkStatsServiceTest { private @Mock INetworkManagementService mNetManager; private @Mock NetworkStatsSettings mSettings; - private @Mock IConnectivityManager mConnManager; private @Mock IBinder mBinder; private @Mock AlarmManager mAlarmManager; private HandlerThread mHandlerThread; @@ -205,7 +203,6 @@ public class NetworkStatsServiceTest { Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService); mHandler = new Handler(mHandlerThread.getLooper(), callback); mService.setHandler(mHandler, callback); - mService.bindConnectivityManager(mConnManager); mElapsedRealtime = 0L; @@ -234,7 +231,6 @@ public class NetworkStatsServiceTest { mNetManager = null; mSettings = null; - mConnManager = null; mSession.close(); mService = null; @@ -245,12 +241,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -289,12 +285,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -363,12 +359,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // modify some number on wifi, and trigger poll event @@ -405,12 +401,12 @@ public class NetworkStatsServiceTest { public void testUidStatsAcrossNetworks() throws Exception { // pretend first mobile network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some traffic on first network @@ -437,7 +433,7 @@ public class NetworkStatsServiceTest { // disappearing, to verify we don't count backwards. incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_2)); + states = new NetworkState[] {buildMobile3gState(IMSI_2)}; expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) @@ -446,7 +442,7 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); forcePollAndWaitForIdle(); @@ -481,12 +477,12 @@ public class NetworkStatsServiceTest { public void testUidRemovedIsMoved() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some traffic @@ -540,12 +536,12 @@ public class NetworkStatsServiceTest { public void testUid3g4gCombinedByTemplate() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some traffic @@ -566,14 +562,14 @@ public class NetworkStatsServiceTest { // now switch over to 4g network incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); - expectNetworkState(buildMobile4gState(TEST_IFACE2)); + states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); forcePollAndWaitForIdle(); @@ -598,12 +594,12 @@ public class NetworkStatsServiceTest { public void testSummaryForAllUid() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some traffic for two apps @@ -657,12 +653,12 @@ public class NetworkStatsServiceTest { public void testDetailedUidStats() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); NetworkStats.Entry entry1 = new NetworkStats.Entry( TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L); @@ -700,13 +696,13 @@ public class NetworkStatsServiceTest { stackedProp.setInterfaceName(stackedIface); final NetworkState wifiState = buildWifiState(); wifiState.linkProperties.addStackedLink(stackedProp); - expectNetworkState(wifiState); + NetworkState[] states = new NetworkState[] {wifiState}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); NetworkStats.Entry uidStats = new NetworkStats.Entry( TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L); @@ -745,12 +741,12 @@ public class NetworkStatsServiceTest { public void testForegroundBackground() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some initial traffic @@ -803,12 +799,12 @@ public class NetworkStatsServiceTest { public void testMetered() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState(true /* isMetered */)); + NetworkState[] states = new NetworkState[] {buildWifiState(true /* isMetered */)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some initial traffic @@ -843,12 +839,13 @@ public class NetworkStatsServiceTest { public void testRoaming() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */)); + NetworkState[] states = + new NetworkState[] {buildMobile3gState(IMSI_1, true /* isRoaming */)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // Create some traffic @@ -882,12 +879,12 @@ public class NetworkStatsServiceTest { public void testTethering() throws Exception { // pretend first mobile network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some tethering traffic @@ -925,12 +922,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -1077,11 +1074,11 @@ public class NetworkStatsServiceTest { expectBandwidthControlCheck(); } - private void expectNetworkState(NetworkState... state) throws Exception { - when(mConnManager.getAllNetworkState()).thenReturn(state); - - final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null; - when(mConnManager.getActiveLinkProperties()).thenReturn(linkProp); + private String getActiveIface(NetworkState... states) throws Exception { + if (states == null || states.length == 0 || states[0].linkProperties == null) { + return null; + } + return states[0].linkProperties.getInterfaceName(); } private void expectNetworkStatsSummary(NetworkStats summary) throws Exception { @@ -1090,8 +1087,6 @@ public class NetworkStatsServiceTest { private void expectNetworkStatsSummary(NetworkStats summary, NetworkStats tetherStats) throws Exception { - when(mConnManager.getAllVpnInfo()).thenReturn(new VpnInfo[0]); - expectNetworkStatsTethering(STATS_PER_IFACE, tetherStats); expectNetworkStatsSummaryDev(summary.clone()); expectNetworkStatsSummaryXt(summary.clone()); From f8525286b446d9fd552d84d96caa1334df871bc3 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 28 Feb 2019 12:06:45 -0700 Subject: [PATCH 026/130] All Parcelable CREATOR fields are @NonNull. If they were null, then the Parcelable would fail to work. Bug: 126726802 Test: manual Change-Id: I7929ffa2f20e5de1c8e68e8263cca99496e9d014 Exempt-From-Owner-Approval: Trivial API annotations --- core/java/android/net/CaptivePortal.java | 2 +- core/java/android/net/ConnectionInfo.java | 2 +- core/java/android/net/DhcpInfo.java | 2 +- core/java/android/net/IpConfiguration.java | 2 +- core/java/android/net/IpPrefix.java | 2 +- core/java/android/net/KeepalivePacketData.java | 2 +- core/java/android/net/LinkAddress.java | 2 +- core/java/android/net/LinkProperties.java | 2 +- core/java/android/net/MacAddress.java | 2 +- core/java/android/net/Network.java | 2 +- core/java/android/net/NetworkCapabilities.java | 2 +- core/java/android/net/NetworkInfo.java | 2 +- core/java/android/net/NetworkMisc.java | 2 +- core/java/android/net/NetworkRequest.java | 2 +- core/java/android/net/NetworkState.java | 2 +- core/java/android/net/ProxyInfo.java | 2 +- core/java/android/net/RouteInfo.java | 2 +- core/java/android/net/StaticIpConfiguration.java | 2 +- core/java/android/net/TcpKeepalivePacketData.java | 2 +- core/java/android/net/UidRange.java | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java index 3ab35e1eeb..f208724820 100644 --- a/core/java/android/net/CaptivePortal.java +++ b/core/java/android/net/CaptivePortal.java @@ -61,7 +61,7 @@ public class CaptivePortal implements Parcelable { out.writeStrongBinder(mBinder); } - public static final Parcelable.Creator CREATOR + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public CaptivePortal createFromParcel(Parcel in) { diff --git a/core/java/android/net/ConnectionInfo.java b/core/java/android/net/ConnectionInfo.java index 58d0e05be6..4514a8484d 100644 --- a/core/java/android/net/ConnectionInfo.java +++ b/core/java/android/net/ConnectionInfo.java @@ -54,7 +54,7 @@ public final class ConnectionInfo implements Parcelable { out.writeInt(remote.getPort()); } - public static final Creator CREATOR = new Creator() { + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public ConnectionInfo createFromParcel(Parcel in) { int protocol = in.readInt(); InetAddress localAddress; diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index 788d7d94f6..98bab44e19 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -84,7 +84,7 @@ public class DhcpInfo implements Parcelable { } /** Implement the Parcelable interface {@hide} */ - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public DhcpInfo createFromParcel(Parcel in) { DhcpInfo info = new DhcpInfo(); diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java index 3319f33878..2af82d7214 100644 --- a/core/java/android/net/IpConfiguration.java +++ b/core/java/android/net/IpConfiguration.java @@ -189,7 +189,7 @@ public class IpConfiguration implements Parcelable { } /** Implement the Parcelable interface */ - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public IpConfiguration createFromParcel(Parcel in) { IpConfiguration config = new IpConfiguration(); diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java index 175263f0ad..21bbd304a8 100644 --- a/core/java/android/net/IpPrefix.java +++ b/core/java/android/net/IpPrefix.java @@ -285,7 +285,7 @@ public final class IpPrefix implements Parcelable { /** * Implement the Parcelable interface. */ - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public IpPrefix createFromParcel(Parcel in) { byte[] address = in.createByteArray(); diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java index 18726f748d..9b8b7322cd 100644 --- a/core/java/android/net/KeepalivePacketData.java +++ b/core/java/android/net/KeepalivePacketData.java @@ -105,7 +105,7 @@ public class KeepalivePacketData implements Parcelable { } /** Parcelable Creator */ - public static final Parcelable.Creator CREATOR = + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { public KeepalivePacketData createFromParcel(Parcel in) { return new KeepalivePacketData(in); diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 8d779aaa23..dcf64d5384 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -356,7 +356,7 @@ public class LinkAddress implements Parcelable { /** * Implement the Parcelable interface. */ - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public LinkAddress createFromParcel(Parcel in) { InetAddress address = null; diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 42db0fd7cb..b52b15e6dd 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -1574,7 +1574,7 @@ public final class LinkProperties implements Parcelable { /** * Implement the Parcelable interface. */ - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public LinkProperties createFromParcel(Parcel in) { LinkProperties netProp = new LinkProperties(); diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 77d83f5ff3..aa8e01046a 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -167,7 +167,7 @@ public final class MacAddress implements Parcelable { return 0; } - public static final Parcelable.Creator CREATOR = + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { public MacAddress createFromParcel(Parcel in) { return new MacAddress(in.readLong()); diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index e04b5fc5f9..0fafdf76b4 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -470,7 +470,7 @@ public class Network implements Parcelable { dest.writeInt(netId); } - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public Network createFromParcel(Parcel in) { int netId = in.readInt(); diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 1d2d81dc4f..a17ebcbedd 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -1442,7 +1442,7 @@ public final class NetworkCapabilities implements Parcelable { dest.writeString(mSSID); } - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public NetworkCapabilities createFromParcel(Parcel in) { diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 89d99617df..cd835317a3 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -557,7 +557,7 @@ public class NetworkInfo implements Parcelable { } } - public static final Creator CREATOR = new Creator() { + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public NetworkInfo createFromParcel(Parcel in) { int netType = in.readInt(); diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java index c0487b521b..ed0b61efd7 100644 --- a/core/java/android/net/NetworkMisc.java +++ b/core/java/android/net/NetworkMisc.java @@ -100,7 +100,7 @@ public class NetworkMisc implements Parcelable { out.writeInt(skip464xlat ? 1 : 0); } - public static final Creator CREATOR = new Creator() { + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public NetworkMisc createFromParcel(Parcel in) { NetworkMisc networkMisc = new NetworkMisc(); diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 9508217be5..dcb027d187 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -363,7 +363,7 @@ public class NetworkRequest implements Parcelable { dest.writeInt(requestId); dest.writeString(type.name()); } - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public NetworkRequest createFromParcel(Parcel in) { NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in); diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index 97fb3fb772..292cf50ac4 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -87,7 +87,7 @@ public class NetworkState implements Parcelable { } @UnsupportedAppUsage - public static final Creator CREATOR = new Creator() { + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public NetworkState createFromParcel(Parcel in) { return new NetworkState(in); diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index ef2269a145..807c467053 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -342,7 +342,7 @@ public class ProxyInfo implements Parcelable { dest.writeStringArray(mParsedExclusionList); } - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public ProxyInfo createFromParcel(Parcel in) { String host = null; diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 5c0f758209..c1c8f6eaf3 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -486,7 +486,7 @@ public final class RouteInfo implements Parcelable { /** * Implement the Parcelable interface. */ - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public RouteInfo createFromParcel(Parcel in) { IpPrefix dest = in.readParcelable(null); diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java index 99cf3a99f5..8b264eeee3 100644 --- a/core/java/android/net/StaticIpConfiguration.java +++ b/core/java/android/net/StaticIpConfiguration.java @@ -212,7 +212,7 @@ public final class StaticIpConfiguration implements Parcelable { } /** Implement the Parcelable interface */ - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public StaticIpConfiguration createFromParcel(Parcel in) { return readFromParcel(in); diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/core/java/android/net/TcpKeepalivePacketData.java index f07dfb64cd..99d36c504e 100644 --- a/core/java/android/net/TcpKeepalivePacketData.java +++ b/core/java/android/net/TcpKeepalivePacketData.java @@ -194,7 +194,7 @@ public class TcpKeepalivePacketData extends KeepalivePacketData implements Parce } /** Parcelable Creator. */ - public static final Parcelable.Creator CREATOR = + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { public TcpKeepalivePacketData createFromParcel(Parcel in) { return new TcpKeepalivePacketData(in); diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java index 793c82dc68..d4a4cf4367 100644 --- a/core/java/android/net/UidRange.java +++ b/core/java/android/net/UidRange.java @@ -91,7 +91,7 @@ public final class UidRange extends UidRangeParcel { * The parceling code is autogenerated by the superclass. */ - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public UidRange createFromParcel(Parcel in) { From 20f6eea87c372154df84d34c971a3aebd309a076 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 27 Feb 2019 14:56:11 +0800 Subject: [PATCH 027/130] Add tethering event callback API Provide OnTetheringEventCallback for system app to know tethering's upstream. Bug: 125583822 Test: -build, flash, boot -atest FrameworksNetTests Change-Id: I7ca81b27c9b805cc01884509f5b20d9d0a24cd36 --- .../java/android/net/ConnectivityManager.java | 89 +++++++++++++++++++ .../android/net/IConnectivityManager.aidl | 4 + .../android/server/ConnectivityService.java | 17 ++++ 3 files changed, 110 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 0497f8c946..fb0821e735 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -56,6 +56,7 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseIntArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.Preconditions; @@ -2541,6 +2542,94 @@ public class ConnectivityManager { } } + /** + * Callback for use with {@link registerTetheringEventCallback} to find out tethering + * upstream status. + * + *@hide + */ + @SystemApi + public abstract static class OnTetheringEventCallback { + + /** + * Called when tethering upstream changed. This can be called multiple times and can be + * called any time. + * + * @param network the {@link Network} of tethering upstream. Null means tethering doesn't + * have any upstream. + */ + public void onUpstreamChanged(@Nullable Network network) {} + } + + @GuardedBy("mTetheringEventCallbacks") + private final ArrayMap + mTetheringEventCallbacks = new ArrayMap<>(); + + /** + * Start listening to tethering change events. Any new added callback will receive the last + * tethering status right away. If callback is registered when tethering loses its upstream or + * disabled, {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called + * with a null argument. The same callback object cannot be registered twice. + * + * @param executor the executor on which callback will be invoked. + * @param callback the callback to be called when tethering has change events. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + public void registerTetheringEventCallback( + @NonNull @CallbackExecutor Executor executor, + @NonNull final OnTetheringEventCallback callback) { + Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null."); + + synchronized (mTetheringEventCallbacks) { + Preconditions.checkArgument(!mTetheringEventCallbacks.containsKey(callback), + "callback was already registered."); + ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() { + @Override + public void onUpstreamChanged(Network network) throws RemoteException { + Binder.withCleanCallingIdentity(() -> + executor.execute(() -> { + callback.onUpstreamChanged(network); + })); + } + }; + try { + String pkgName = mContext.getOpPackageName(); + Log.i(TAG, "registerTetheringUpstreamCallback:" + pkgName); + mService.registerTetheringEventCallback(remoteCallback, pkgName); + mTetheringEventCallbacks.put(callback, remoteCallback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Remove tethering event callback previously registered with + * {@link #registerTetheringEventCallback}. + * + * @param callback previously registered callback. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) + public void unregisterTetheringEventCallback( + @NonNull final OnTetheringEventCallback callback) { + synchronized (mTetheringEventCallbacks) { + ITetheringEventCallback remoteCallback = mTetheringEventCallbacks.remove(callback); + Preconditions.checkNotNull(remoteCallback, "callback was not registered."); + try { + String pkgName = mContext.getOpPackageName(); + Log.i(TAG, "unregisterTetheringEventCallback:" + pkgName); + mService.unregisterTetheringEventCallback(remoteCallback, pkgName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** * Get the list of regular expressions that define any tetherable * USB network interfaces. If USB tethering is not supported by the diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index fd44fc8a23..a425a91ef3 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -19,6 +19,7 @@ package android.net; import android.app.PendingIntent; import android.net.ConnectionInfo; import android.net.LinkProperties; +import android.net.ITetheringEventCallback; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; @@ -214,4 +215,7 @@ interface IConnectivityManager void getLatestTetheringEntitlementResult(int type, in ResultReceiver receiver, boolean showEntitlementUi, String callerPkg); + + void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); + void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 219e046595..199477ce26 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -71,6 +71,7 @@ import android.net.INetworkMonitorCallbacks; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; +import android.net.ITetheringEventCallback; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkProperties; @@ -3798,6 +3799,22 @@ public class ConnectivityService extends IConnectivityManager.Stub mTethering.getLatestTetheringEntitlementResult(type, receiver, showEntitlementUi); } + /** Register tethering event callback. */ + @Override + public void registerTetheringEventCallback(ITetheringEventCallback callback, + String callerPkg) { + ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); + mTethering.registerTetheringEventCallback(callback); + } + + /** Unregister tethering event callback. */ + @Override + public void unregisterTetheringEventCallback(ITetheringEventCallback callback, + String callerPkg) { + ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg); + mTethering.unregisterTetheringEventCallback(callback); + } + // Called when we lose the default network and have no replacement yet. // This will automatically be cleared after X seconds or a new default network // becomes CONNECTED, whichever happens first. The timer is started by the From 9d4479a4f482c0aec8f31abf109ff258b9b885cd Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Thu, 21 Feb 2019 14:24:24 -0800 Subject: [PATCH 028/130] Add uid information in PackageListObserver The uid information of a removed package cannot be retrieved by the packageName anymore once it is removed. So it would be useful to provide the uid of removed package in the onPackageAdded and onPackageRemoved method of the PackageListObserver. This modification helps simplify the design in PermissionMonitor. Bug: 125396053 Test: dumpsys netd trafficcontroller Change-Id: I2bd4bdf924687960a4fa3a47235bae68d885e445 --- .../connectivity/PermissionMonitor.java | 51 ++++++------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index d84a4d2db9..123564eb4f 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -46,13 +46,11 @@ import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; -import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.LocalServices; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -84,20 +82,14 @@ public class PermissionMonitor { // Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission. private final Map mApps = new HashMap<>(); - // Keys are App packageNames, Values are app uids. . We need to keep track of this information - // because PackageListObserver#onPackageRemoved does not pass the UID. - @GuardedBy("mPackageNameUidMap") - private final Map mPackageNameUidMap = new HashMap<>(); - private class PackageListObserver implements PackageManagerInternal.PackageListObserver { @Override - public void onPackageAdded(String packageName) { + public void onPackageAdded(String packageName, int uid) { final PackageInfo app = getPackageInfo(packageName); if (app == null) { Slog.wtf(TAG, "Failed to get information of installed package: " + packageName); return; } - int uid = (app.applicationInfo != null) ? app.applicationInfo.uid : INVALID_UID; if (uid == INVALID_UID) { Slog.wtf(TAG, "Failed to get the uid of installed package: " + packageName + "uid: " + uid); @@ -107,29 +99,21 @@ public class PermissionMonitor { return; } sendPackagePermissionsForUid(uid, - filterPermission(Arrays.asList(app.requestedPermissions))); - synchronized (mPackageNameUidMap) { - mPackageNameUidMap.put(packageName, uid); - } + getNetdPermissionMask(app.requestedPermissions)); } @Override - public void onPackageRemoved(String packageName) { - int uid; - synchronized (mPackageNameUidMap) { - if (!mPackageNameUidMap.containsKey(packageName)) { - return; - } - uid = mPackageNameUidMap.get(packageName); - mPackageNameUidMap.remove(packageName); - } + public void onPackageRemoved(String packageName, int uid) { int permission = 0; + // If there are still packages remain under the same uid, check the permission of the + // remaining packages. We only remove the permission for a given uid when all packages + // for that uid no longer have that permission. String[] packages = mPackageManager.getPackagesForUid(uid); if (packages != null && packages.length > 0) { for (String name : packages) { final PackageInfo app = getPackageInfo(name); if (app != null && app.requestedPermissions != null) { - permission |= filterPermission(Arrays.asList(app.requestedPermissions)); + permission |= getNetdPermissionMask(app.requestedPermissions); } } } @@ -184,12 +168,9 @@ public class PermissionMonitor { //TODO: unify the management of the permissions into one codepath. if (app.requestedPermissions != null) { - int otherNetdPerms = filterPermission(Arrays.asList(app.requestedPermissions)); + int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions); if (otherNetdPerms != 0) { netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms); - synchronized (mPackageNameUidMap) { - mPackageNameUidMap.put(app.applicationInfo.packageName, uid); - } } } } @@ -422,13 +403,15 @@ public class PermissionMonitor { } } - private static int filterPermission(List requestedPermissions) { + private static int getNetdPermissionMask(String[] requestedPermissions) { int permissions = 0; - if (requestedPermissions.contains(INTERNET)) { - permissions |= INetd.PERMISSION_INTERNET; - } - if (requestedPermissions.contains(UPDATE_DEVICE_STATS)) { - permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS; + for (String permissionName : requestedPermissions) { + if (permissionName.equals(INTERNET)) { + permissions |= INetd.PERMISSION_INTERNET; + } + if (permissionName.equals(UPDATE_DEVICE_STATS)) { + permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS; + } } return permissions; } @@ -439,8 +422,6 @@ public class PermissionMonitor { | MATCH_ANY_USER); return app; } catch (NameNotFoundException e) { - // App not found. - loge("NameNotFoundException " + packageName); return null; } } From b36a811d5869864722539d1bde2725c0130feecd Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 9 Nov 2018 14:45:34 -0800 Subject: [PATCH 029/130] Integrate testNetworkService and Manager with Connectivity stack This change adds TestAPIs for tests to retrive an instance of ConnectivityManager, allowing it to build test TUN interfaces, as well as test networks. This also integrates the TestNetwork types with ConnectivityManager, creating virtual networks if the network agent is a test agent. Bug: 72950854 Test: Compiles, CTS tests using this passing correctly Change-Id: I741ef9cdf4bd4125d9129af3a030edf32f438e4f --- .../android/net/IConnectivityManager.aidl | 2 ++ .../android/server/ConnectivityService.java | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 403b44d6d7..f1e4f64ef8 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -219,4 +219,6 @@ interface IConnectivityManager void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg); + + IBinder startOrGetTestNetworkService(); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 72f7a68ad2..3ed294845d 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -299,6 +299,15 @@ public class ConnectivityService extends IConnectivityManager.Stub private INetworkPolicyManager mPolicyManager; private NetworkPolicyManagerInternal mPolicyManagerInternal; + /** + * TestNetworkService (lazily) created upon first usage. Locked to prevent creation of multiple + * instances. + */ + @GuardedBy("mTNSLock") + private TestNetworkService mTNS; + + private final Object mTNSLock = new Object(); + private String mCurrentTcpBufferSizes; private static final SparseArray sMagicDecoderRing = MessageUtils.findMessageNames( @@ -6958,4 +6967,22 @@ public class ConnectivityService extends IConnectivityManager.Stub return vpn != null && vpn.getLockdown(); } } + + /** + * Returns a IBinder to a TestNetworkService. Will be lazily created as needed. + * + *

The TestNetworkService must be run in the system server due to TUN creation. + */ + @Override + public IBinder startOrGetTestNetworkService() { + synchronized (mTNSLock) { + TestNetworkService.enforceTestNetworkPermissions(mContext); + + if (mTNS == null) { + mTNS = new TestNetworkService(mContext, mNMS); + } + + return mTNS; + } + } } From 1d2fb104301d2003f3b15ac018d58d7a3af03e57 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 14 Mar 2019 15:42:09 -0700 Subject: [PATCH 030/130] Moved transport to IntDef Moved out from the sub class per API review feedback. Test: Build Bug: 128607082 Change-Id: I1b513bcaaa0ebf47c14593d962579ed48a7c6db0 --- .../server/connectivity/NetworkNotificationManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index 053da0d5b1..828a1e5886 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -28,6 +28,7 @@ import android.content.Intent; import android.content.res.Resources; import android.net.wifi.WifiInfo; import android.os.UserHandle; +import android.telephony.AccessNetworkConstants.TransportType; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; @@ -92,7 +93,7 @@ public class NetworkNotificationManager { return -1; } - private static String getTransportName(int transportType) { + private static String getTransportName(@TransportType int transportType) { Resources r = Resources.getSystem(); String[] networkTypes = r.getStringArray(R.array.network_switch_type_name); try { From 86b51bb8a4e6fcb7c371645543c3c5585bdb4c76 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 18 Mar 2019 23:50:34 +0900 Subject: [PATCH 031/130] Stop using netd parcelables in the framework. The only actual users of these classes are in services.jar, not in frameworks.jar. The only reason the framework depends on them is that the code that converts to and from stable parcelables is currently in the framework. Move that code to services and cut the dependency. These classes aren't used in the networkstack app so they don't need to be in shared. They also can't be in shared because the classes are not in the SDK. So put the conversion functions directly inside their only user (NetworkManagementService). Also remove the jarjar rules that rename the classes for use by the NetworkStack app. This does not actually remove the dependency from the build file, that will be done in a future CL. Bug: 128804404 Test: builds, boots Test: atest FrameworksNetTests android.net.cts.ConnectivityManagerTest HostsideVpnTests Change-Id: I027d50ba56091f5558f45e6e08f32e5912b2a82a --- core/java/android/net/UidRange.java | 31 ++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java index d4a4cf4367..e56f05995c 100644 --- a/core/java/android/net/UidRange.java +++ b/core/java/android/net/UidRange.java @@ -19,14 +19,17 @@ package android.net; import static android.os.UserHandle.PER_USER_RANGE; import android.os.Parcel; +import android.os.Parcelable; /** * An inclusive range of UIDs. * * @hide */ -public final class UidRange extends UidRangeParcel { - private UidRange() {} +public final class UidRange implements Parcelable { + public final int start; + public final int stop; + public UidRange(int startUid, int stopUid) { if (startUid < 0) throw new IllegalArgumentException("Invalid start UID."); if (stopUid < 0) throw new IllegalArgumentException("Invalid stop UID."); @@ -86,18 +89,28 @@ public final class UidRange extends UidRangeParcel { return start + "-" + stop; } - /** - * DO NOT override "writeToParcel" and "readFromParcel" in this class. - * The parceling code is autogenerated by the superclass. - */ + // Implement the Parcelable interface + // TODO: Consider making this class no longer parcelable, since all users are likely in the + // system server. + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(start); + dest.writeInt(stop); + } public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public UidRange createFromParcel(Parcel in) { - UidRange obj = new UidRange(); - obj.readFromParcel(in); - return obj; + int start = in.readInt(); + int stop = in.readInt(); + + return new UidRange(start, stop); } @Override public UidRange[] newArray(int size) { From 47002ed0d11e3f4174a17427e04a89a421ba62ce Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 19 Mar 2019 00:24:19 +0900 Subject: [PATCH 032/130] Move TcpKeepalivePacketData out of the framework. This class is not used in framework.jar, only in services.jar. Move it out of the framework so framework.jar can stop depending on the NetworkStack stable AIDL interfaces. This should really under com.android.server as well, but that's a cross-project change to be done in another CL. Test: m Bug: 128804404 Change-Id: Ib2805f7fcc516a5f6989c252365d1c95b8042703 --- .../android/net/TcpKeepalivePacketData.java | 234 ------------------ 1 file changed, 234 deletions(-) delete mode 100644 core/java/android/net/TcpKeepalivePacketData.java diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/core/java/android/net/TcpKeepalivePacketData.java deleted file mode 100644 index 99d36c504e..0000000000 --- a/core/java/android/net/TcpKeepalivePacketData.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2019 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 android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.SocketKeepalive.InvalidPacketException; -import android.net.util.IpUtils; -import android.os.Parcel; -import android.os.Parcelable; -import android.system.OsConstants; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** - * Represents the actual tcp keep alive packets which will be used for hardware offload. - * @hide - */ -public class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable { - private static final String TAG = "TcpKeepalivePacketData"; - - /** TCP sequence number. */ - public final int tcpSeq; - - /** TCP ACK number. */ - public final int tcpAck; - - /** TCP RCV window. */ - public final int tcpWnd; - - /** TCP RCV window scale. */ - public final int tcpWndScale; - - private static final int IPV4_HEADER_LENGTH = 20; - private static final int IPV6_HEADER_LENGTH = 40; - private static final int TCP_HEADER_LENGTH = 20; - - // This should only be constructed via static factory methods, such as - // tcpKeepalivePacket. - private TcpKeepalivePacketData(TcpSocketInfo tcpDetails, byte[] data) - throws InvalidPacketException { - super(tcpDetails.srcAddress, tcpDetails.srcPort, tcpDetails.dstAddress, - tcpDetails.dstPort, data); - tcpSeq = tcpDetails.seq; - tcpAck = tcpDetails.ack; - // In the packet, the window is shifted right by the window scale. - tcpWnd = tcpDetails.rcvWnd; - tcpWndScale = tcpDetails.rcvWndScale; - } - - /** - * Factory method to create tcp keepalive packet structure. - */ - public static TcpKeepalivePacketData tcpKeepalivePacket( - TcpSocketInfo tcpDetails) throws InvalidPacketException { - final byte[] packet; - if ((tcpDetails.srcAddress instanceof Inet4Address) - && (tcpDetails.dstAddress instanceof Inet4Address)) { - packet = buildV4Packet(tcpDetails); - } else { - // TODO: support ipv6 - throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS); - } - - return new TcpKeepalivePacketData(tcpDetails, packet); - } - - /** - * Build ipv4 tcp keepalive packet, not including the link-layer header. - */ - // TODO : if this code is ever moved to the network stack, factorize constants with the ones - // over there. - private static byte[] buildV4Packet(TcpSocketInfo tcpDetails) { - final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH; - ByteBuffer buf = ByteBuffer.allocate(length); - buf.order(ByteOrder.BIG_ENDIAN); - // IP version and TOS. TODO : fetch this from getsockopt(SOL_IP, IP_TOS) - buf.putShort((short) 0x4500); - buf.putShort((short) length); - buf.putInt(0x4000); // ID, flags=DF, offset - // TODO : fetch TTL from getsockopt(SOL_IP, IP_TTL) - buf.put((byte) 64); - buf.put((byte) OsConstants.IPPROTO_TCP); - final int ipChecksumOffset = buf.position(); - buf.putShort((short) 0); // IP checksum - buf.put(tcpDetails.srcAddress.getAddress()); - buf.put(tcpDetails.dstAddress.getAddress()); - buf.putShort((short) tcpDetails.srcPort); - buf.putShort((short) tcpDetails.dstPort); - buf.putInt(tcpDetails.seq); // Sequence Number - buf.putInt(tcpDetails.ack); // ACK - buf.putShort((short) 0x5010); // TCP length=5, flags=ACK - buf.putShort((short) (tcpDetails.rcvWnd >> tcpDetails.rcvWndScale)); // Window size - final int tcpChecksumOffset = buf.position(); - buf.putShort((short) 0); // TCP checksum - // URG is not set therefore the urgent pointer is not included - buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0)); - buf.putShort(tcpChecksumOffset, IpUtils.tcpChecksum( - buf, 0, IPV4_HEADER_LENGTH, TCP_HEADER_LENGTH)); - - return buf.array(); - } - - // TODO: add buildV6Packet. - - /** Represents tcp/ip information. */ - // TODO: Replace TcpSocketInfo with TcpKeepalivePacketDataParcelable. - public static class TcpSocketInfo { - public final InetAddress srcAddress; - public final InetAddress dstAddress; - public final int srcPort; - public final int dstPort; - public final int seq; - public final int ack; - public final int rcvWnd; - public final int rcvWndScale; - - public TcpSocketInfo(InetAddress sAddr, int sPort, InetAddress dAddr, - int dPort, int writeSeq, int readSeq, int rWnd, int rWndScale) { - srcAddress = sAddr; - dstAddress = dAddr; - srcPort = sPort; - dstPort = dPort; - seq = writeSeq; - ack = readSeq; - rcvWnd = rWnd; - rcvWndScale = rWndScale; - } - } - - @Override - public boolean equals(@Nullable final Object o) { - if (!(o instanceof TcpKeepalivePacketData)) return false; - final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o; - return this.srcAddress.equals(other.srcAddress) - && this.dstAddress.equals(other.dstAddress) - && this.srcPort == other.srcPort - && this.dstPort == other.dstPort - && this.tcpAck == other.tcpAck - && this.tcpSeq == other.tcpSeq - && this.tcpWnd == other.tcpWnd - && this.tcpWndScale == other.tcpWndScale; - } - - @Override - public int hashCode() { - return Objects.hash(srcAddress, dstAddress, srcPort, dstPort, tcpAck, tcpSeq, tcpWnd, - tcpWndScale); - } - - /* Parcelable Implementation. */ - /* Note that this object implements parcelable (and needs to keep doing this as it inherits - * from a class that does), but should usually be parceled as a stable parcelable using - * the toStableParcelable() and fromStableParcelable() methods. - */ - public int describeContents() { - return 0; - } - - /** Write to parcel. */ - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeInt(tcpSeq); - out.writeInt(tcpAck); - out.writeInt(tcpWnd); - out.writeInt(tcpWndScale); - } - - private TcpKeepalivePacketData(Parcel in) { - super(in); - tcpSeq = in.readInt(); - tcpAck = in.readInt(); - tcpWnd = in.readInt(); - tcpWndScale = in.readInt(); - } - - /** Parcelable Creator. */ - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public TcpKeepalivePacketData createFromParcel(Parcel in) { - return new TcpKeepalivePacketData(in); - } - - public TcpKeepalivePacketData[] newArray(int size) { - return new TcpKeepalivePacketData[size]; - } - }; - - /** - * Convert this TcpKeepalivePacketData to a TcpKeepalivePacketDataParcelable. - */ - @NonNull - public TcpKeepalivePacketDataParcelable toStableParcelable() { - final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable(); - parcel.srcAddress = srcAddress.getAddress(); - parcel.srcPort = srcPort; - parcel.dstAddress = dstAddress.getAddress(); - parcel.dstPort = dstPort; - parcel.seq = tcpSeq; - parcel.ack = tcpAck; - return parcel; - } - - @Override - public String toString() { - return "saddr: " + srcAddress - + " daddr: " + dstAddress - + " sport: " + srcPort - + " dport: " + dstPort - + " seq: " + tcpSeq - + " ack: " + tcpAck - + " wnd: " + tcpWnd - + " wndScale: " + tcpWndScale; - } -} From d6d5505edf7af25854a12e532af38e259acf54a7 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 22 Mar 2019 17:16:52 +0900 Subject: [PATCH 033/130] Fix API in CaptivePortal and ConnectivityManager - Remove CaptivePortal constructor from SystemApi. This constructor was added in Q timeframe and ends up being unnecessary since CaptivePortal creation was refactored to ConnectivityService because of visibility issues on ICaptivePortal. - Rename getAvoidBadWifi to shouldAvoidBadWifi - Add permission annotation for shouldAvoidBadWifi Test: flashed, WiFi and captive portal works Bug: 128935314 Bug: 128935673 (clean cherry-pick of AOSP I7395d4a4db6a64398a827692aee1956c011873e5) Change-Id: I09545c00af3519dbf141dd5951b28f49e37b3e80 --- core/java/android/net/CaptivePortal.java | 2 -- core/java/android/net/ConnectivityManager.java | 7 +++++-- core/java/android/net/IConnectivityManager.aidl | 2 +- .../core/java/com/android/server/ConnectivityService.java | 8 ++++++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java index 3e4e35a8f1..133943226c 100644 --- a/core/java/android/net/CaptivePortal.java +++ b/core/java/android/net/CaptivePortal.java @@ -64,8 +64,6 @@ public class CaptivePortal implements Parcelable { private final IBinder mBinder; /** @hide */ - @SystemApi - @TestApi public CaptivePortal(@NonNull IBinder binder) { mBinder = binder; } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 16322353ad..428c2e7bc0 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -4101,9 +4101,12 @@ public class ConnectivityManager { * @hide */ @SystemApi - public boolean getAvoidBadWifi() { + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public boolean shouldAvoidBadWifi() { try { - return mService.getAvoidBadWifi(); + return mService.shouldAvoidBadWifi(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 24e6a855ff..61648dc7f1 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -182,7 +182,7 @@ interface IConnectivityManager void startCaptivePortalApp(in Network network); void startCaptivePortalAppInternal(in Network network, in Bundle appExtras); - boolean getAvoidBadWifi(); + boolean shouldAvoidBadWifi(); int getMultipathPreference(in Network Network); NetworkRequest getDefaultRequest(); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ec5987e97c..cab969791e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3470,8 +3470,12 @@ public class ConnectivityService extends IConnectivityManager.Stub return mMultinetworkPolicyTracker.getAvoidBadWifi(); } - @Override - public boolean getAvoidBadWifi() { + /** + * Return whether the device should maintain continuous, working connectivity by switching away + * from WiFi networks having no connectivity. + * @see MultinetworkPolicyTracker#getAvoidBadWifi() + */ + public boolean shouldAvoidBadWifi() { if (!checkNetworkStackPermission()) { throw new SecurityException("avoidBadWifi requires NETWORK_STACK permission"); } From 8472116bff9a5dbf57d4ad34934eea699ec5c696 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 1 Feb 2019 14:20:32 +0900 Subject: [PATCH 034/130] Straighten AIDL interface for the memory store Some names were still wrong somehow, and the wrappers were missing. Test: NetworkStack & FrameworkNetTests Change-Id: I475bd011ad9bc714a07021a9dfd85c4876f8e9ad --- .../android/server/net/ipmemorystore/NetworkAttributesTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fb84611cb6..a83faf3477 100644 --- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java +++ b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.net.ipmemorystore; +package com.android.server.connectivity.ipmemorystore; import static org.junit.Assert.assertEquals; From 6566d1b82f09e814c900c0c9b24f03d6cdfdc357 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Fri, 1 Mar 2019 15:07:24 -0800 Subject: [PATCH 035/130] Move NetworkStatsFactory into service directory In order to notify netd to swap eBPF maps before pulling the networkStats from eBPF maps, NetworkStatsFactory need to use the NetdServices to issue binder calls. So it need to be moved from framework/base/core to framework/base/service since object in framework/base/core cannot get any system services. This change is also necessary for setting up a lock inside NetworkStatsFactory to prevent racing between two netstats caller since the lock need to be hold before netd trigger the map swap. Also fix the compile problem caused by moving the NetworkStatsFactory and the related tests. Rename the packages and the jni functions to a more proper name. Bug: 124764595 Bug: 128900919 Test: NetworkStatsFactoryTest android.app.usage.cts.NetworkUsageStatsTest android.net.cts.TrafficStatsTest Change-Id: Ifcfe4df81caf8ede2e4e66a76552cb3200378fa8 --- tests/net/Android.bp | 54 +++++++++++++++++-- .../net/NetworkStatsFactoryTest.java | 6 ++- 2 files changed, 54 insertions(+), 6 deletions(-) rename tests/net/java/com/android/{internal => server}/net/NetworkStatsFactoryTest.java (96%) diff --git a/tests/net/Android.bp b/tests/net/Android.bp index c62d85e418..70b408949d 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -1,11 +1,8 @@ //######################################################################## // Build FrameworksNetTests package //######################################################################## - -android_test { - name: "FrameworksNetTests", - // Include all test java files. - srcs: ["java/**/*.java"], +java_defaults { + name: "FrameworksNetTests-jni-defaults", static_libs: [ "frameworks-base-testutils", "framework-protos", @@ -20,6 +17,53 @@ android_test { "android.test.base", "android.test.mock", ], + jni_libs: [ + "ld-android", + "libartbase", + "libbacktrace", + "libbase", + "libbinder", + "libbinderthreadstate", + "libbpf", + "libbpf_android", + "libc++", + "libcgrouprc", + "libcrypto", + "libcutils", + "libdexfile", + "libdl_android", + "libhidl-gen-utils", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libjsoncpp", + "liblog", + "liblzma", + "libnativehelper", + "libnetdbpf", + "libnetdutils", + "libpackagelistparser", + "libpcre2", + "libprocessgroup", + "libselinux", + "libui", + "libutils", + "libvintf", + "libvndksupport", + "libtinyxml2", + "libunwindstack", + "libutilscallstack", + "libziparchive", + "libz", + "netd_aidl_interface-cpp", + "libnetworkstatsfactorytestjni", + ], +} + +android_test { + name: "FrameworksNetTests", + defaults: ["FrameworksNetTests-jni-defaults"], + srcs: ["java/**/*.java"], platform_apis: true, test_suites: ["device-tests"], certificate: "platform", diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java similarity index 96% rename from tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java rename to tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java index 4ec4fdd80a..95bc7d92d5 100644 --- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.net; +package com.android.server.net; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.METERED_NO; @@ -70,6 +70,10 @@ public class NetworkStatsFactoryTest { IoUtils.deleteContents(mTestProc); } + // The libandroid_servers which have the native method is not available to + // applications. So in order to have a test support native library, the native code + // related to networkStatsFactory is compiled to a minimal native library and loaded here. + System.loadLibrary("networkstatsfactorytestjni"); mFactory = new NetworkStatsFactory(mTestProc, false); } From fb21e4697bc3271fe139461c8d7d91c04671d35e Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Apr 2019 09:47:10 -0700 Subject: [PATCH 036/130] Add common tests for FrameworksBaseTests and CTS The common package covers tests that should be included both in CTS and unit tests. Test: atest FrameworksBaseTests Bug: 129199908 Change-Id: Ic78ff947250871fa773252c924f1dee9395c6074 (cherry picked from commit 054e3e0f5ebfffe5d9fdd0095abac309552ae0cd) --- tests/net/Android.bp | 1 + tests/net/common/Android.bp | 29 +++++++ .../java/android/net/IpPrefixTest.java | 80 +++++++++---------- 3 files changed, 70 insertions(+), 40 deletions(-) create mode 100644 tests/net/common/Android.bp rename tests/net/{ => common}/java/android/net/IpPrefixTest.java (85%) diff --git a/tests/net/Android.bp b/tests/net/Android.bp index 70b408949d..c8ef82ec9a 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -4,6 +4,7 @@ java_defaults { name: "FrameworksNetTests-jni-defaults", static_libs: [ + "FrameworksNetCommonTests", "frameworks-base-testutils", "framework-protos", "androidx.test.rules", diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp new file mode 100644 index 0000000000..0a1ac75aac --- /dev/null +++ b/tests/net/common/Android.bp @@ -0,0 +1,29 @@ +// +// Copyright (C) 2019 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. +// + +// Tests in this folder are included both in unit tests and CTS. +// They must be fast and stable, and exercise public or test APIs. +java_library { + name: "FrameworksNetCommonTests", + srcs: ["java/**/*.java"], + static_libs: [ + "androidx.test.rules", + "junit", + ], + libs: [ + "android.test.base.stubs", + ], +} \ No newline at end of file diff --git a/tests/net/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java similarity index 85% rename from tests/net/java/android/net/IpPrefixTest.java rename to tests/net/common/java/android/net/IpPrefixTest.java index abf019afed..719960d486 100644 --- a/tests/net/java/android/net/IpPrefixTest.java +++ b/tests/net/common/java/android/net/IpPrefixTest.java @@ -39,7 +39,7 @@ import java.util.Random; @SmallTest public class IpPrefixTest { - private static InetAddress Address(String addr) { + private static InetAddress address(String addr) { return InetAddress.parseNumericAddress(addr); } @@ -58,59 +58,59 @@ public class IpPrefixTest { try { p = new IpPrefix((byte[]) null, 9); fail("Expected NullPointerException: null byte array"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { p = new IpPrefix((InetAddress) null, 10); fail("Expected NullPointerException: null InetAddress"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { p = new IpPrefix((String) null); fail("Expected NullPointerException: null String"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { byte[] b2 = {1, 2, 3, 4, 5}; p = new IpPrefix(b2, 29); fail("Expected IllegalArgumentException: invalid array length"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("1.2.3.4"); fail("Expected IllegalArgumentException: no prefix length"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("1.2.3.4/"); fail("Expected IllegalArgumentException: empty prefix length"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("foo/32"); fail("Expected IllegalArgumentException: invalid address"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("1/32"); fail("Expected IllegalArgumentException: deprecated IPv4 format"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("1.2.3.256/32"); fail("Expected IllegalArgumentException: invalid IPv4 address"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("foo/32"); fail("Expected IllegalArgumentException: non-address"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } try { p = new IpPrefix("f00:::/32"); fail("Expected IllegalArgumentException: invalid IPv6 address"); - } catch(IllegalArgumentException expected) {} + } catch (IllegalArgumentException expected) { } } @Test @@ -132,17 +132,17 @@ public class IpPrefixTest { try { p = new IpPrefix(IPV4_BYTES, 33); fail("Expected IllegalArgumentException: invalid prefix length"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { p = new IpPrefix(IPV4_BYTES, 128); fail("Expected IllegalArgumentException: invalid prefix length"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { p = new IpPrefix(IPV4_BYTES, -1); fail("Expected IllegalArgumentException: negative prefix length"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } p = new IpPrefix(IPV6_BYTES, 128); assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString()); @@ -162,12 +162,12 @@ public class IpPrefixTest { try { p = new IpPrefix(IPV6_BYTES, -1); fail("Expected IllegalArgumentException: negative prefix length"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } try { p = new IpPrefix(IPV6_BYTES, 129); fail("Expected IllegalArgumentException: negative prefix length"); - } catch(RuntimeException expected) {} + } catch (RuntimeException expected) { } } @@ -226,28 +226,28 @@ public class IpPrefixTest { @Test public void testContainsInetAddress() { IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127"); - assertTrue(p.contains(Address("2001:db8:f00::ace:d00c"))); - assertTrue(p.contains(Address("2001:db8:f00::ace:d00d"))); - assertFalse(p.contains(Address("2001:db8:f00::ace:d00e"))); - assertFalse(p.contains(Address("2001:db8:f00::bad:d00d"))); - assertFalse(p.contains(Address("2001:4868:4860::8888"))); - assertFalse(p.contains(Address("8.8.8.8"))); + assertTrue(p.contains(address("2001:db8:f00::ace:d00c"))); + assertTrue(p.contains(address("2001:db8:f00::ace:d00d"))); + assertFalse(p.contains(address("2001:db8:f00::ace:d00e"))); + assertFalse(p.contains(address("2001:db8:f00::bad:d00d"))); + assertFalse(p.contains(address("2001:4868:4860::8888"))); + assertFalse(p.contains(address("8.8.8.8"))); p = new IpPrefix("192.0.2.0/23"); - assertTrue(p.contains(Address("192.0.2.43"))); - assertTrue(p.contains(Address("192.0.3.21"))); - assertFalse(p.contains(Address("192.0.0.21"))); - assertFalse(p.contains(Address("8.8.8.8"))); - assertFalse(p.contains(Address("2001:4868:4860::8888"))); + assertTrue(p.contains(address("192.0.2.43"))); + assertTrue(p.contains(address("192.0.3.21"))); + assertFalse(p.contains(address("192.0.0.21"))); + assertFalse(p.contains(address("8.8.8.8"))); + assertFalse(p.contains(address("2001:4868:4860::8888"))); IpPrefix ipv6Default = new IpPrefix("::/0"); - assertTrue(ipv6Default.contains(Address("2001:db8::f00"))); - assertFalse(ipv6Default.contains(Address("192.0.2.1"))); + assertTrue(ipv6Default.contains(address("2001:db8::f00"))); + assertFalse(ipv6Default.contains(address("192.0.2.1"))); IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0"); - assertTrue(ipv4Default.contains(Address("255.255.255.255"))); - assertTrue(ipv4Default.contains(Address("192.0.2.1"))); - assertFalse(ipv4Default.contains(Address("2001:db8::f00"))); + assertTrue(ipv4Default.contains(address("255.255.255.255"))); + assertTrue(ipv4Default.contains(address("192.0.2.1"))); + assertFalse(ipv4Default.contains(address("2001:db8::f00"))); } @Test @@ -315,10 +315,10 @@ public class IpPrefixTest { p = new IpPrefix(b, random.nextInt(129)); } if (p.equals(oldP)) { - assertEquals(p.hashCode(), oldP.hashCode()); + assertEquals(p.hashCode(), oldP.hashCode()); } if (p.hashCode() != oldP.hashCode()) { - assertNotEquals(p, oldP); + assertNotEquals(p, oldP); } } } @@ -332,9 +332,9 @@ public class IpPrefixTest { new IpPrefix("0.0.0.0/0"), }; for (int i = 0; i < prefixes.length; i++) { - for (int j = i + 1; j < prefixes.length; j++) { - assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode()); - } + for (int j = i + 1; j < prefixes.length; j++) { + assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode()); + } } } @@ -371,8 +371,8 @@ public class IpPrefixTest { } public void assertParcelingIsLossless(IpPrefix p) { - IpPrefix p2 = passThroughParcel(p); - assertEquals(p, p2); + IpPrefix p2 = passThroughParcel(p); + assertEquals(p, p2); } @Test From 1da5fac070d8b2936abee19362698895a78b484f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 5 Apr 2019 04:44:45 -0700 Subject: [PATCH 037/130] Move attach*Filter() and addArpEntry() methods to NetworkStack The SocketUtils.attach*Filter and SocketUtils.addArpEntry methods were added there because they could not be added as JNI inside the NetworkStack. This was not possible because on Go devices, the NetworkStack was a jar library. But now, Go also uses an APK. Hence, move these methods to the NetworkStack. Fixes: 129433183 Merged-In: I66d7b3e4fbfa32bb0bc853e8cf9399031daff8a9 (cherry picked from commit fe71be2b04a3213828dc0347a1dd4a3675d20562) Change-Id: Ice433a41469e784385f19498c154345d7b9c69b5 --- core/java/android/net/NetworkUtils.java | 39 ----- core/jni/android_net_NetUtils.cpp | 198 ------------------------ 2 files changed, 237 deletions(-) diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 5188866fe4..db87c97e4f 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -29,7 +29,6 @@ import android.util.Log; import android.util.Pair; import java.io.FileDescriptor; -import java.io.IOException; import java.math.BigInteger; import java.net.Inet4Address; import java.net.Inet6Address; @@ -49,32 +48,6 @@ public class NetworkUtils { private static final String TAG = "NetworkUtils"; - /** - * Attaches a socket filter that accepts DHCP packets to the given socket. - */ - @UnsupportedAppUsage - public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException; - - /** - * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket. - * @param fd the socket's {@link FileDescriptor}. - * @param packetType the hardware address type, one of ARPHRD_*. - */ - @UnsupportedAppUsage - public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException; - - /** - * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity. - * - * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges. - * - * @param fd the socket's {@link FileDescriptor}. - * @param packetType the hardware address type, one of ARPHRD_*. - */ - @UnsupportedAppUsage - public native static void attachControlPacketFilter(FileDescriptor fd, int packetType) - throws SocketException; - /** * Attaches a socket filter that drops all of incoming packets. * @param fd the socket's {@link FileDescriptor}. @@ -182,18 +155,6 @@ public class NetworkUtils { */ public static native void resNetworkCancel(FileDescriptor fd); - /** - * Add an entry into the ARP cache. - */ - public static void addArpEntry(Inet4Address ipv4Addr, MacAddress ethAddr, String ifname, - FileDescriptor fd) throws IOException { - addArpEntry(ethAddr.toByteArray(), ipv4Addr.getAddress(), ifname, fd); - } - - private static native void addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname, - FileDescriptor fd) throws IOException; - - /** * Get the tcp repair window associated with the {@code fd}. * diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 82acf6fb43..dd754f35bb 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -48,17 +48,6 @@ int ifc_disable(const char *ifname); namespace android { -static const uint32_t kEtherTypeOffset = offsetof(ether_header, ether_type); -static const uint32_t kEtherHeaderLen = sizeof(ether_header); -static const uint32_t kIPv4Protocol = kEtherHeaderLen + offsetof(iphdr, protocol); -static const uint32_t kIPv4FlagsOffset = kEtherHeaderLen + offsetof(iphdr, frag_off); -static const uint32_t kIPv6NextHeader = kEtherHeaderLen + offsetof(ip6_hdr, ip6_nxt); -static const uint32_t kIPv6PayloadStart = kEtherHeaderLen + sizeof(ip6_hdr); -static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type); -static const uint32_t kUDPSrcPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, source); -static const uint32_t kUDPDstPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, dest); -static const uint16_t kDhcpClientPort = 68; - constexpr int MAXPACKETSIZE = 8 * 1024; // FrameworkListener limits the size of commands to 1024 bytes. TODO: fix this. constexpr int MAXCMDSIZE = 1024; @@ -84,149 +73,6 @@ static void throwErrnoException(JNIEnv* env, const char* functionName, int error env->Throw(reinterpret_cast(exception)); } -static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd) -{ - struct sock_filter filter_code[] = { - // Check the protocol is UDP. - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 6), - - // Check this is not a fragment. - BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset), - BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_OFFMASK, 4, 0), - - // Get the IP header length. - BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen), - - // Check the destination port. - BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPDstPortIndirectOffset), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 0, 1), - - // Accept or reject. - BPF_STMT(BPF_RET | BPF_K, 0xffff), - BPF_STMT(BPF_RET | BPF_K, 0) - }; - struct sock_fprog filter = { - sizeof(filter_code) / sizeof(filter_code[0]), - filter_code, - }; - - int fd = jniGetFDFromFileDescriptor(env, javaFd); - if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno)); - } -} - -static void android_net_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd, - jint hardwareAddressType) -{ - if (hardwareAddressType != ARPHRD_ETHER) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "attachRaFilter only supports ARPHRD_ETHER"); - return; - } - - struct sock_filter filter_code[] = { - // Check IPv6 Next Header is ICMPv6. - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeader), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3), - - // Check ICMPv6 type is Router Advertisement. - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_ADVERT, 0, 1), - - // Accept or reject. - BPF_STMT(BPF_RET | BPF_K, 0xffff), - BPF_STMT(BPF_RET | BPF_K, 0) - }; - struct sock_fprog filter = { - sizeof(filter_code) / sizeof(filter_code[0]), - filter_code, - }; - - int fd = jniGetFDFromFileDescriptor(env, javaFd); - if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno)); - } -} - -// TODO: Move all this filter code into libnetutils. -static void android_net_utils_attachControlPacketFilter( - JNIEnv *env, jobject clazz, jobject javaFd, jint hardwareAddressType) { - if (hardwareAddressType != ARPHRD_ETHER) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "attachControlPacketFilter only supports ARPHRD_ETHER"); - return; - } - - // Capture all: - // - ARPs - // - DHCPv4 packets - // - Router Advertisements & Solicitations - // - Neighbor Advertisements & Solicitations - // - // tcpdump: - // arp or - // '(ip and udp port 68)' or - // '(icmp6 and ip6[40] >= 133 and ip6[40] <= 136)' - struct sock_filter filter_code[] = { - // Load the link layer next payload field. - BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kEtherTypeOffset), - - // Accept all ARP. - // TODO: Figure out how to better filter ARPs on noisy networks. - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_ARP, 16, 0), - - // If IPv4: - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IP, 0, 9), - - // Check the protocol is UDP. - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 14), - - // Check this is not a fragment. - BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset), - BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_OFFMASK, 12, 0), - - // Get the IP header length. - BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen), - - // Check the source port. - BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPSrcPortIndirectOffset), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 8, 0), - - // Check the destination port. - BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPDstPortIndirectOffset), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 6, 7), - - // IPv6 ... - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IPV6, 0, 6), - // ... check IPv6 Next Header is ICMPv6 (ignore fragments), ... - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeader), - BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 4), - // ... and check the ICMPv6 type is one of RS/RA/NS/NA. - BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset), - BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, ND_ROUTER_SOLICIT, 0, 2), - BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, ND_NEIGHBOR_ADVERT, 1, 0), - - // Accept or reject. - BPF_STMT(BPF_RET | BPF_K, 0xffff), - BPF_STMT(BPF_RET | BPF_K, 0) - }; - struct sock_fprog filter = { - sizeof(filter_code) / sizeof(filter_code[0]), - filter_code, - }; - - int fd = jniGetFDFromFileDescriptor(env, javaFd); - if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) { - jniThrowExceptionFmt(env, "java/net/SocketException", - "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno)); - } -} - static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd) { struct sock_filter filter_code[] = { @@ -389,46 +235,6 @@ static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* return true; } -static void android_net_utils_addArpEntry(JNIEnv *env, jobject thiz, jbyteArray ethAddr, - jbyteArray ipv4Addr, jstring ifname, jobject javaFd) -{ - struct arpreq req = {}; - struct sockaddr_in& netAddrStruct = *reinterpret_cast(&req.arp_pa); - struct sockaddr& ethAddrStruct = req.arp_ha; - - ethAddrStruct.sa_family = ARPHRD_ETHER; - if (!checkLenAndCopy(env, ethAddr, ETH_ALEN, ethAddrStruct.sa_data)) { - jniThrowException(env, "java/io/IOException", "Invalid ethAddr length"); - return; - } - - netAddrStruct.sin_family = AF_INET; - if (!checkLenAndCopy(env, ipv4Addr, sizeof(in_addr), &netAddrStruct.sin_addr)) { - jniThrowException(env, "java/io/IOException", "Invalid ipv4Addr length"); - return; - } - - int ifLen = env->GetStringLength(ifname); - // IFNAMSIZ includes the terminating NULL character - if (ifLen >= IFNAMSIZ) { - jniThrowException(env, "java/io/IOException", "ifname too long"); - return; - } - env->GetStringUTFRegion(ifname, 0, ifLen, req.arp_dev); - - req.arp_flags = ATF_COM; // Completed entry (ha valid) - int fd = jniGetFDFromFileDescriptor(env, javaFd); - if (fd < 0) { - jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor"); - return; - } - // See also: man 7 arp - if (ioctl(fd, SIOCSARP, &req)) { - jniThrowExceptionFmt(env, "java/io/IOException", "ioctl error: %s", strerror(errno)); - return; - } -} - static jobject android_net_utils_resNetworkQuery(JNIEnv *env, jobject thiz, jint netId, jstring dname, jint ns_class, jint ns_type, jint flags) { const jsize javaCharsCount = env->GetStringLength(dname); @@ -542,10 +348,6 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork }, { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn }, { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess }, - { "addArpEntry", "([B[BLjava/lang/String;Ljava/io/FileDescriptor;)V", (void*) android_net_utils_addArpEntry }, - { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter }, - { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter }, - { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachControlPacketFilter }, { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter }, { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter }, { "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow }, From cd1fec890706650fb380791b5cfbe49e63092e93 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 4 Apr 2019 09:18:29 -0700 Subject: [PATCH 038/130] Fix flaky UdpEncapsulationSocket test This commit reduces the flakiness of the testOpenAndCloseUdpEncapsulationSocket by retrying up to three times. Unfortunately, testing port-selected socket creation is racy against other applications. This helps to handle the same race condition as done in IpSecService#bindToRandomPort Bug: 128024100 Test: 200x runs of testOpenAndCloseUdpEncapsulationSocket Change-Id: I7e036ce821019dbac6c50899bd0894e89d2fe82a Merged-In: Idf040a67e53d9b9ec6e6c647ce24f8ada501d355 Merged-In: Iad9aea4b42cd8b31a5a2659bb9cb54dd1c64e8b7 (cherry picked from commit 614ab3dd4e49e9b664f5065983fb9067148fef12) --- .../com/android/server/IpSecServiceTest.java | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java index b5c3e92874..4a35015044 100644 --- a/tests/net/java/com/android/server/IpSecServiceTest.java +++ b/tests/net/java/com/android/server/IpSecServiceTest.java @@ -156,10 +156,21 @@ public class IpSecServiceTest { @Test public void testOpenAndCloseUdpEncapsulationSocket() throws Exception { - int localport = findUnusedPort(); + int localport = -1; + IpSecUdpEncapResponse udpEncapResp = null; + + for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) { + localport = findUnusedPort(); + + udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); + assertNotNull(udpEncapResp); + if (udpEncapResp.status == IpSecManager.Status.OK) { + break; + } + + // Else retry to reduce possibility for port-bind failures. + } - IpSecUdpEncapResponse udpEncapResp = - mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); assertNotNull(udpEncapResp); assertEquals(IpSecManager.Status.OK, udpEncapResp.status); assertEquals(localport, udpEncapResp.port); @@ -204,12 +215,11 @@ public class IpSecServiceTest { @Test public void testOpenUdpEncapsulationSocketAfterClose() throws Exception { - int localport = findUnusedPort(); IpSecUdpEncapResponse udpEncapResp = - mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); + mIpSecService.openUdpEncapsulationSocket(0, new Binder()); assertNotNull(udpEncapResp); assertEquals(IpSecManager.Status.OK, udpEncapResp.status); - assertEquals(localport, udpEncapResp.port); + int localport = udpEncapResp.port; mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId); udpEncapResp.fileDescriptor.close(); @@ -226,12 +236,11 @@ public class IpSecServiceTest { */ @Test public void testUdpEncapPortNotReleased() throws Exception { - int localport = findUnusedPort(); IpSecUdpEncapResponse udpEncapResp = - mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); + mIpSecService.openUdpEncapsulationSocket(0, new Binder()); assertNotNull(udpEncapResp); assertEquals(IpSecManager.Status.OK, udpEncapResp.status); - assertEquals(localport, udpEncapResp.port); + int localport = udpEncapResp.port; udpEncapResp.fileDescriptor.close(); @@ -273,14 +282,11 @@ public class IpSecServiceTest { @Test public void testOpenUdpEncapsulationSocketTwice() throws Exception { - int localport = findUnusedPort(); - IpSecUdpEncapResponse udpEncapResp = - mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); + mIpSecService.openUdpEncapsulationSocket(0, new Binder()); assertNotNull(udpEncapResp); assertEquals(IpSecManager.Status.OK, udpEncapResp.status); - assertEquals(localport, udpEncapResp.port); - mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); + int localport = udpEncapResp.port; IpSecUdpEncapResponse testUdpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder()); From 7a9206fcdcdc9130488c5d638f186b63170fb391 Mon Sep 17 00:00:00 2001 From: Anil Admal Date: Mon, 8 Apr 2019 12:36:02 -0700 Subject: [PATCH 039/130] Extend support for requestRouteToHostAddress for backward compatibility The gnss@2.0 HAL and the framework GNSS Location Provider code is updated in Q to not call the deprecated requestRouteToHost() method. However, devices upgrading to Q which are still using gnss@1.1 or earlier HAL must continued to be supported. Fixes: 121222025 Test: Tested with gnss@1.1 HAL and first API level P. The ConnectivityService log message "This method exists only for app backwards compatibility and must not be called by system services" is not present for devices with first API level P. Change-Id: I10199776ea413dc256dbf0771e6cb3eedb334495 Merged-In: Ifa60d8f2d60aba4c4e2894dc612c224d45e3992d Merged-In: Ifa4ec98d5c942522dfd569664f169fa841d495ed (cherry picked from commit 2eea7ac272431b6e02a0a281207b981b01daf393) --- .../core/java/com/android/server/ConnectivityService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6405254112..7a5e1b5b04 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -133,6 +133,7 @@ import android.os.ServiceSpecificException; import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -1628,8 +1629,11 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private boolean disallowedBecauseSystemCaller() { // TODO: start throwing a SecurityException when GnssLocationProvider stops calling - // requestRouteToHost. - if (isSystem(Binder.getCallingUid())) { + // requestRouteToHost. In Q, GnssLocationProvider is changed to not call requestRouteToHost + // for devices launched with Q and above. However, existing devices upgrading to Q and + // above must continued to be supported for few more releases. + if (isSystem(Binder.getCallingUid()) && SystemProperties.getInt( + "ro.product.first_api_level", 0) > Build.VERSION_CODES.P) { log("This method exists only for app backwards compatibility" + " and must not be called by system services."); return true; From b375738a52cb316e8ed283ece6aa8f877fe6b2f2 Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 4 Apr 2019 00:57:26 -0700 Subject: [PATCH 040/130] Fix ConnectivityServiceTest fail. NetdService#getInstance() will get null object in WrappedConnectivityService constructor. Then pass this null INetd object to PermissionMonitor will case NPE in PermissionMonitor#sendPackagePermissionsToNetd() Bug: 128024100 Test: atest FrameworksNetTests Change-Id: Ia1c80f9600a19c4aaf3f3c1b497b355d96c49c8e Merged-In: I7f185e731db91c30a9b0f14aefbdbb067942190e Merged-In: Ic77ef73841266da487401ffd657ef63562b6fc1e (cherry picked from commit 7d215078521ea03bbd692364e882d02ad065ced0) --- .../com/android/server/connectivity/PermissionMonitor.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index da1360d595..b6946023e8 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -469,7 +469,10 @@ public class PermissionMonitor { */ @VisibleForTesting void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) { - + if (mNetd == null) { + Log.e(TAG, "Failed to get the netd service"); + return; + } ArrayList allPermissionAppIds = new ArrayList<>(); ArrayList internetPermissionAppIds = new ArrayList<>(); ArrayList updateStatsPermissionAppIds = new ArrayList<>(); From fd95136ad9b95a70a2becd062f3e77e7c2534f39 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 8 Apr 2019 20:28:44 +0900 Subject: [PATCH 041/130] Address leftover comments on aosp/894233 Cherry-pick from commit 415f523f7ce4c7e33fa70ea003f265e5b53faa20, with small conflict resolution. Bug: 129510344 Test: m, boots, wifi connects, resolves DNS Change-Id: Idf24f42a86bbfcc89e3ea8cf50d1b705d72ac613 Merged-In: Idf24f42a86bbfcc89e3ea8cf50d1b705d72ac613 Merged-In: Ia08104f839ef37139a8761e2e625bb10c94c275f --- .../core/java/com/android/server/ConnectivityService.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6405254112..60b1a2dc5d 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1767,11 +1767,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // caller type. Need to re-factor NetdEventListenerService to allow multiple // NetworkMonitor registrants. if (nai != null && nai.satisfies(mDefaultRequest)) { - try { - nai.networkMonitor().notifyDnsResponse(returnCode); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } + Binder.withCleanCallingIdentity(() -> + nai.networkMonitor().notifyDnsResponse(returnCode)); } } From 608168402b0b88b251e587aa1856ac79f4d0e265 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 9 Apr 2019 11:31:46 -0700 Subject: [PATCH 042/130] Fix remove-before-add for IpSecService RefcountedResource This patch fixes a bug where if a binder dies before the linkToDeath call, the cleanup will be performed before the entry is added to the array. While it is safe in that quotas and tracking performs as per normal, the RefcountedRecord may not be cleaned up. Rethrowing this exception is safe, since the only paths that would hit this are all on binder threads coming from applications. Further, it seems there is only one real way of this getting hit - if the app that called the creation died during the binder call. Bug: 126802451 Test: Compiled, CTS tests passing Change-Id: Ib955acaa5e498c0e977cb5f2e48cffbc9fea8c7c Merged-In: I6db75853da9f29e1573512e26351623f22770c5d Merged-In: I416c2e43961ec0e1cc6b2fbcef970fbce858603b Merged-In: Ib955acaa5e498c0e977cb5f2e48cffbc9fea8c7c (cherry picked from commit 6c089d90bfa728e9842de0f5947f0c557c62dea0) --- .../server/IpSecServiceRefcountedResourceTest.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java index 68ff777a01..22a2c94fc1 100644 --- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java +++ b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java @@ -18,6 +18,7 @@ package com.android.server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.eq; @@ -134,11 +135,11 @@ public class IpSecServiceRefcountedResourceTest { IBinder binderMock = mock(IBinder.class); doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt()); - RefcountedResource refcountedResource = getTestRefcountedResource(binderMock); - - // Verify that cleanup is performed (Spy limitations prevent verification of method calls - // for binder death scenario; check refcount to determine if cleanup was performed.) - assertEquals(-1, refcountedResource.mRefCount); + try { + getTestRefcountedResource(binderMock); + fail("Expected exception to propogate when binder fails to link to death"); + } catch (RuntimeException expected) { + } } @Test From e2fd1e9c6de96fc16c0d55a56ed2a49e091ad87c Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 9 Apr 2019 02:04:54 -0700 Subject: [PATCH 043/130] Expose captive portal urls for configuration Carriers in Mainland China need to customize certain captive portal urls. The main issue is that google servers are not accessible in Mainland China. Added the following captive portal resources to be targeted for overlay. - config_captive_portal_http_url - config_captive_portal_https_url - config_captive_portal_fallback_urls (string-array) - config_captive_portal_fallback_probe_specs (string-array) These values can be customized for e g diffent countries Bug: 111819230 Test: atest FrameworksNetTests NetworkStackTests Test: Add a product RRO that targets a specific country code, insert a SIM card that matches that country code and check the log what URL is used. Merged-In: I54050b28bbfb93e0b7e509dbe0e987a0b902b7d9 Merged-In: I1f734c5f864bb2f2bc8ba1a66fe33d3480554f69 (cherry picked from commit 2977a40b1e8db190e5974a638b2619b3d253d38b) Change-Id: I278f2888851d38edb59157f8623541fbe94549b6 --- .../android/server/ConnectivityService.java | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 57de67e1a3..d9b92a664d 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -108,7 +108,6 @@ import android.net.VpnService; import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.netlink.InetDiagMessage; -import android.net.shared.NetworkMonitorUtils; import android.net.shared.PrivateDnsConfig; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; @@ -238,6 +237,16 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final boolean LOGD_BLOCKED_NETWORKINFO = true; + /** + * Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed + * by OEMs for configuration purposes, as this value is overridden by + * Settings.Global.CAPTIVE_PORTAL_HTTP_URL. + * R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose + * (preferably via runtime resource overlays). + */ + private static final String DEFAULT_CAPTIVE_PORTAL_HTTP_URL = + "http://connectivitycheck.gstatic.com/generate_204"; + // TODO: create better separation between radio types and network types // how long to wait before switching back to a radio's default network @@ -6701,9 +6710,20 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String getCaptivePortalServerUrl() { enforceConnectivityInternalPermission(); - final String defaultUrl = mContext.getResources().getString( - R.string.config_networkDefaultCaptivePortalServerUrl); - return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(mContext, defaultUrl); + String settingUrl = mContext.getResources().getString( + R.string.config_networkCaptivePortalServerUrl); + + if (!TextUtils.isEmpty(settingUrl)) { + return settingUrl; + } + + settingUrl = Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.CAPTIVE_PORTAL_HTTP_URL); + if (!TextUtils.isEmpty(settingUrl)) { + return settingUrl; + } + + return DEFAULT_CAPTIVE_PORTAL_HTTP_URL; } @Override From cc6836e90856913475c3d2d789e90739122f5542 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 9 Apr 2019 08:59:00 -0700 Subject: [PATCH 044/130] Fix onBlockedStatusChanged does not work on multiple networks There is a logic error in maybeNotifyNetworkBlockedForNewUidRules that caused function to return if there is no status change in the first network. This would cause CTS failed in devices which has volte-enabled SIM inserted. Bug: 129409153 Fix: 117969394 Test: 1. atest com.android.cts.net.HostsideNetworkCallbackTests \ --generate-new-metrics 20 2. atest FrameworksNetTests Change-Id: I11168fd07a7c29e0605f2e874e9d9f41b5ad88b6 Merged-In: Ifd18d1c6ad708c1dbc793f03d8241f572af50317 (cherry picked from commit 794f01c7266275fa4b22a5ce37fe992535d04463) --- services/core/java/com/android/server/ConnectivityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 57de67e1a3..f5490d777e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -6543,7 +6543,7 @@ public class ConnectivityService extends IConnectivityManager.Stub uid, newRules, metered, mRestrictBackground); } if (oldBlocked == newBlocked) { - return; + continue; } final int arg = encodeBool(newBlocked); for (int i = 0; i < nai.numNetworkRequests(); i++) { From 28a989488865ace132421c4aeb823cc32cbdfcf8 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 11 Apr 2019 04:59:16 -0700 Subject: [PATCH 045/130] Add support for TAP interfaces in TestNetworkManager. Bug: 72950854 Test: builds, boots Change-Id: I88bfd7f37c0ba0228f8288fe92212618ce134e4f Merged-In: I88bfd7f37c0ba0228f8288fe92212618ce134e4f (cherry picked from commit ba2eb5e0621c4f2a2c86a641998b4ae1953ae4b8) --- core/java/android/net/TestNetworkManager.java | 17 ++++++++ .../android/server/TestNetworkService.java | 39 +++++++++++++++---- .../com_android_server_TestNetworkService.cpp | 12 +++--- 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java index cd58e6641e..ba26c1ff13 100644 --- a/core/java/android/net/TestNetworkManager.java +++ b/core/java/android/net/TestNetworkManager.java @@ -88,4 +88,21 @@ public class TestNetworkManager { throw e.rethrowFromSystemServer(); } } + + /** + * Create a tap interface for testing purposes + * + * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the + * TAP interface. + * @hide + */ + @TestApi + public TestNetworkInterface createTapInterface() { + try { + return mService.createTapInterface(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index e64ab78d1e..6f2df3f234 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -60,6 +60,7 @@ 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_TUN_PREFIX = "testtun"; + @NonNull private static final String TEST_TAP_PREFIX = "testtap"; @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger(); @NonNull private final Context mContext; @@ -70,7 +71,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { @NonNull private final Handler mHandler; // Native method stubs - private static native int jniCreateTun(@NonNull String iface); + private static native int jniCreateTunTap(boolean isTun, @NonNull String iface); @VisibleForTesting protected TestNetworkService( @@ -85,23 +86,23 @@ class TestNetworkService extends ITestNetworkManager.Stub { } /** - * Create a TUN interface with the given interface name and link addresses + * Create a TUN or TAP interface with the given interface name and link addresses * - *

This method will return the FileDescriptor to the TUN interface. Close it to tear down the - * TUN interface. + *

This method will return the FileDescriptor to the interface. Close it to tear down the + * interface. */ - @Override - public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) { + private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) { enforceTestNetworkPermissions(mContext); checkNotNull(linkAddrs, "missing linkAddrs"); - String iface = TEST_TUN_PREFIX + sTestTunIndex.getAndIncrement(); + String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX; + String iface = ifacePrefix + sTestTunIndex.getAndIncrement(); return Binder.withCleanCallingIdentity( () -> { try { ParcelFileDescriptor tunIntf = - ParcelFileDescriptor.adoptFd(jniCreateTun(iface)); + ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface)); for (LinkAddress addr : linkAddrs) { mNetd.interfaceAddAddress( iface, @@ -116,6 +117,28 @@ class TestNetworkService extends ITestNetworkManager.Stub { }); } + /** + * Create a TUN interface with the given interface name and link addresses + * + *

This method will return the FileDescriptor to the TUN interface. Close it to tear down the + * TUN interface. + */ + @Override + public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) { + return createInterface(true, linkAddrs); + } + + /** + * Create a TAP interface with the given interface name + * + *

This method will return the FileDescriptor to the TAP interface. Close it to tear down the + * TAP interface. + */ + @Override + public TestNetworkInterface createTapInterface() { + return createInterface(false, new LinkAddress[0]); + } + // Tracker for TestNetworkAgents @GuardedBy("mTestNetworkTracker") @NonNull diff --git a/services/core/jni/com_android_server_TestNetworkService.cpp b/services/core/jni/com_android_server_TestNetworkService.cpp index b90ff233c1..36a6fde361 100644 --- a/services/core/jni/com_android_server_TestNetworkService.cpp +++ b/services/core/jni/com_android_server_TestNetworkService.cpp @@ -54,12 +54,12 @@ static void throwException(JNIEnv* env, int error, const char* action, const cha jniThrowException(env, "java/lang/IllegalStateException", msg.c_str()); } -static int createTunInterface(JNIEnv* env, const char* iface) { +static int createTunTapInterface(JNIEnv* env, bool isTun, const char* iface) { base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK)); ifreq ifr{}; // Allocate interface. - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + ifr.ifr_flags = (isTun ? IFF_TUN : IFF_TAP) | IFF_NO_PI; strlcpy(ifr.ifr_name, iface, IFNAMSIZ); if (ioctl(tun.get(), TUNSETIFF, &ifr)) { throwException(env, errno, "allocating", ifr.ifr_name); @@ -80,23 +80,23 @@ static int createTunInterface(JNIEnv* env, const char* iface) { //------------------------------------------------------------------------------ -static jint create(JNIEnv* env, jobject /* thiz */, jstring jIface) { +static jint create(JNIEnv* env, jobject /* thiz */, jboolean isTun, jstring jIface) { ScopedUtfChars iface(env, jIface); if (!iface.c_str()) { jniThrowNullPointerException(env, "iface"); return -1; } - int tun = createTunInterface(env, iface.c_str()); + int tun = createTunTapInterface(env, isTun, iface.c_str()); - // Any exceptions will be thrown from the createTunInterface call + // Any exceptions will be thrown from the createTunTapInterface call return tun; } //------------------------------------------------------------------------------ static const JNINativeMethod gMethods[] = { - {"jniCreateTun", "(Ljava/lang/String;)I", (void*)create}, + {"jniCreateTunTap", "(ZLjava/lang/String;)I", (void*)create}, }; int register_android_server_TestNetworkService(JNIEnv* env) { From a66baf749b8174d94bb6a050f5be5b58d6b04d7b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 12 Mar 2019 21:54:16 -0700 Subject: [PATCH 046/130] Cleanup of Test Network service This follow-up change performs some cleanup changes without affecting functionality Bug: 72950854 Test: Compiles, CTS tests using this pass Change-Id: Ic7394f24f11d713c9374b438182e29d2a02ea236 Merged-In: Ic7394f24f11d713c9374b438182e29d2a02ea236 (cherry picked from commit 7df36ed96a807f258aef43e558ef127b27b90756) --- core/java/android/net/TestNetworkInterface.java | 2 -- core/java/android/net/TestNetworkManager.java | 5 +---- .../core/java/com/android/server/TestNetworkService.java | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/TestNetworkInterface.java b/core/java/android/net/TestNetworkInterface.java index 30e68f5b98..84550834be 100644 --- a/core/java/android/net/TestNetworkInterface.java +++ b/core/java/android/net/TestNetworkInterface.java @@ -27,8 +27,6 @@ import android.os.Parcelable; */ @TestApi public final class TestNetworkInterface implements Parcelable { - private static final String TAG = "TestNetworkInterface"; - private final ParcelFileDescriptor mFileDescriptor; private final String mInterfaceName; diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java index cd58e6641e..cfda460474 100644 --- a/core/java/android/net/TestNetworkManager.java +++ b/core/java/android/net/TestNetworkManager.java @@ -17,7 +17,6 @@ package android.net; import android.annotation.NonNull; import android.annotation.TestApi; -import android.content.Context; import android.os.IBinder; import android.os.RemoteException; @@ -33,11 +32,9 @@ public class TestNetworkManager { @NonNull private static final String TAG = TestNetworkManager.class.getSimpleName(); @NonNull private final ITestNetworkManager mService; - @NonNull private final Context mContext; /** @hide */ - public TestNetworkManager(@NonNull Context context, @NonNull ITestNetworkManager service) { - mContext = Preconditions.checkNotNull(context, "missing Context"); + public TestNetworkManager(@NonNull ITestNetworkManager service) { mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager"); } diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index e64ab78d1e..8997d8c3e5 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -310,7 +310,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { public void teardownTestNetwork(int netId) { enforceTestNetworkPermissions(mContext); - TestNetworkAgent agent; + final TestNetworkAgent agent; synchronized (mTestNetworkTracker) { agent = mTestNetworkTracker.get(netId); } From 8fee125db47d1e5ec7412f638fea0ac03def000a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 9 Apr 2019 16:29:43 -0700 Subject: [PATCH 047/130] Enable checks for MANAGE_TEST_NETWORKS in TestNetworkService This commit re-enables enforcement of the MANAGE_TEST_NETWORK permission, which is only granted to the shell. CTS tests using this permission should use UiAutomation.adoptShellPermissionIdentity() to gain access. Bug: 72950854 Test: IPsec CTS tests using this passing Change-Id: I98573a5c68e45abbbaddef01f6ac74a6a18e26f9 Merged-In: I98573a5c68e45abbbaddef01f6ac74a6a18e26f9 (cherry picked from commit 3ec38dc5530db151388879a521d6d3b94679a0de) --- .../java/com/android/server/TestNetworkService.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index 8997d8c3e5..bd20a24468 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -325,14 +325,10 @@ class TestNetworkService extends ITestNetworkManager.Stub { agent.teardown(); } - // STOPSHIP: Change this back to android.Manifest.permission.MANAGE_TEST_NETWORKS - private static final String PERMISSION_NAME = "dummy"; + private static final String PERMISSION_NAME = + android.Manifest.permission.MANAGE_TEST_NETWORKS; public static void enforceTestNetworkPermissions(@NonNull Context context) { - // STOPSHIP: Re-enable these checks. Disabled until adoptShellPermissionIdentity() can be - // called from CTS test code. - if (false) { - context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService"); - } + context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService"); } } From 0494f8833d411c188f1d73166d027a3733b2f5bf Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Thu, 11 Apr 2019 17:54:41 -0700 Subject: [PATCH 048/130] API council feedbacks for DnsResolver To address the API review feedback provided by the API council. Bug: 129261432 Test: atest DnsResolverTest Merged-In: I5737cf293264bf9d492e7bd56b62bee4d49002eb (cherry picked from commit 454fe010dcacd38211b857d2b235ed37269e3b7e) Change-Id: I429dd93285f50314e9d757f4ec8539a3ba40e61b --- core/java/android/net/DnsResolver.java | 282 +++++++++++++----------- core/java/android/net/NetworkUtils.java | 5 +- core/jni/android_net_NetUtils.cpp | 9 +- 3 files changed, 168 insertions(+), 128 deletions(-) diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java index 06c32c675a..b6c4fe2de4 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -93,6 +93,23 @@ public final class DnsResolver { public static final int FLAG_NO_CACHE_STORE = 1 << 1; public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2; + @IntDef(prefix = { "ERROR_" }, value = { + ERROR_PARSE, + ERROR_SYSTEM + }) + @Retention(RetentionPolicy.SOURCE) + @interface DnsError {} + /** + * Indicates that there was an error parsing the response the query. + * The cause of this error is available via getCause() and is a ParseException. + */ + public static final int ERROR_PARSE = 0; + /** + * Indicates that there was an error sending the query. + * The cause of this error is available via getCause() and is an ErrnoException. + */ + public static final int ERROR_SYSTEM = 1; + private static final int NETID_UNSET = 0; private static final DnsResolver sInstance = new DnsResolver(); @@ -107,97 +124,57 @@ public final class DnsResolver { private DnsResolver() {} /** - * Answer parser for parsing raw answers + * Base interface for answer callbacks * - * @param The type of the parsed answer + * @param The type of the answer */ - public interface AnswerParser { - /** - * Creates a answer by parsing the given raw answer. - * - * @param rawAnswer the raw answer to be parsed - * @return a parsed answer - * @throws ParseException if parsing failed - */ - @NonNull T parse(@NonNull byte[] rawAnswer) throws ParseException; - } - - /** - * Base class for answer callbacks - * - * @param The type of the parsed answer - */ - public abstract static class AnswerCallback { - /** @hide */ - public final AnswerParser parser; - - public AnswerCallback(@NonNull AnswerParser parser) { - this.parser = parser; - }; - + public interface Callback { /** * Success response to - * {@link android.net.DnsResolver#query query()}. + * {@link android.net.DnsResolver#query query()} or + * {@link android.net.DnsResolver#rawQuery rawQuery()}. * * Invoked when the answer to a query was successfully parsed. * - * @param answer parsed answer to the query. + * @param answer answer to the query. + * @param rcode The response code in the DNS response. * * {@see android.net.DnsResolver#query query()} */ - public abstract void onAnswer(@NonNull T answer); - + void onAnswer(@NonNull T answer, int rcode); /** * Error response to - * {@link android.net.DnsResolver#query query()}. + * {@link android.net.DnsResolver#query query()} or + * {@link android.net.DnsResolver#rawQuery rawQuery()}. * * Invoked when there is no valid answer to * {@link android.net.DnsResolver#query query()} + * {@link android.net.DnsResolver#rawQuery rawQuery()}. * - * @param exception a {@link ParseException} object with additional + * @param error a {@link DnsException} object with additional * detail regarding the failure */ - public abstract void onParseException(@NonNull ParseException exception); - - /** - * Error response to - * {@link android.net.DnsResolver#query query()}. - * - * Invoked if an error happens when - * issuing the DNS query or receiving the result. - * {@link android.net.DnsResolver#query query()} - * - * @param exception an {@link ErrnoException} object with additional detail - * regarding the failure - */ - public abstract void onQueryException(@NonNull ErrnoException exception); + void onError(@NonNull DnsException error); } /** - * Callback for receiving raw answers + * Class to represent DNS error */ - public abstract static class RawAnswerCallback extends AnswerCallback { - public RawAnswerCallback() { - super(rawAnswer -> rawAnswer); - } - } + public static class DnsException extends Exception { + /** + * DNS error code as one of the ERROR_* constants + */ + @DnsError public final int code; - /** - * Callback for receiving parsed {@link InetAddress} answers - * - * Note that if the answer does not contain any IP addresses, - * onAnswer will be called with an empty list. - */ - public abstract static class InetAddressAnswerCallback - extends AnswerCallback> { - public InetAddressAnswerCallback() { - super(rawAnswer -> new DnsAddressAnswer(rawAnswer).getAddresses()); + DnsException(@DnsError int code, @Nullable Throwable cause) { + super(cause); + this.code = code; } } /** * Send a raw DNS query. - * The answer will be provided asynchronously through the provided {@link AnswerCallback}. + * The answer will be provided asynchronously through the provided {@link Callback}. * * @param network {@link Network} specifying which network to query on. * {@code null} for query on default network. @@ -206,13 +183,13 @@ public final class DnsResolver { * @param executor The {@link Executor} that the callback should be executed on. * @param cancellationSignal used by the caller to signal if the query should be * cancelled. May be {@code null}. - * @param callback an {@link AnswerCallback} which will be called to notify the caller + * @param callback a {@link Callback} which will be called to notify the caller * of the result of dns query. */ - public void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags, + public void rawQuery(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags, @NonNull @CallbackExecutor Executor executor, @Nullable CancellationSignal cancellationSignal, - @NonNull AnswerCallback callback) { + @NonNull Callback callback) { if (cancellationSignal != null && cancellationSignal.isCanceled()) { return; } @@ -222,9 +199,7 @@ public final class DnsResolver { queryfd = resNetworkSend((network != null ? network.netId : NETID_UNSET), query, query.length, flags); } catch (ErrnoException e) { - executor.execute(() -> { - callback.onQueryException(e); - }); + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; } @@ -237,7 +212,7 @@ public final class DnsResolver { /** * Send a DNS query with the specified name, class and query type. - * The answer will be provided asynchronously through the provided {@link AnswerCallback}. + * The answer will be provided asynchronously through the provided {@link Callback}. * * @param network {@link Network} specifying which network to query on. * {@code null} for query on default network. @@ -248,14 +223,14 @@ public final class DnsResolver { * @param executor The {@link Executor} that the callback should be executed on. * @param cancellationSignal used by the caller to signal if the query should be * cancelled. May be {@code null}. - * @param callback an {@link AnswerCallback} which will be called to notify the caller + * @param callback a {@link Callback} which will be called to notify the caller * of the result of dns query. */ - public void query(@Nullable Network network, @NonNull String domain, + public void rawQuery(@Nullable Network network, @NonNull String domain, @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags, @NonNull @CallbackExecutor Executor executor, @Nullable CancellationSignal cancellationSignal, - @NonNull AnswerCallback callback) { + @NonNull Callback callback) { if (cancellationSignal != null && cancellationSignal.isCanceled()) { return; } @@ -265,9 +240,7 @@ public final class DnsResolver { queryfd = resNetworkQuery((network != null ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags); } catch (ErrnoException e) { - executor.execute(() -> { - callback.onQueryException(e); - }); + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; } synchronized (lock) { @@ -277,27 +250,28 @@ public final class DnsResolver { } } - private class InetAddressAnswerAccumulator extends InetAddressAnswerCallback { + private class InetAddressAnswerAccumulator implements Callback { private final List mAllAnswers; - private ParseException mParseException; - private ErrnoException mErrnoException; - private final InetAddressAnswerCallback mUserCallback; + private int mRcode; + private DnsException mDnsException; + private final Callback> mUserCallback; private final int mTargetAnswerCount; private int mReceivedAnswerCount = 0; - InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerCallback callback) { + InetAddressAnswerAccumulator(int size, + @NonNull Callback> callback) { mTargetAnswerCount = size; mAllAnswers = new ArrayList<>(); mUserCallback = callback; } - private boolean maybeReportException() { - if (mErrnoException != null) { - mUserCallback.onQueryException(mErrnoException); + private boolean maybeReportError() { + if (mRcode != 0) { + mUserCallback.onAnswer(mAllAnswers, mRcode); return true; } - if (mParseException != null) { - mUserCallback.onParseException(mParseException); + if (mDnsException != null) { + mUserCallback.onError(mDnsException); return true; } return false; @@ -305,34 +279,43 @@ public final class DnsResolver { private void maybeReportAnswer() { if (++mReceivedAnswerCount != mTargetAnswerCount) return; - if (mAllAnswers.isEmpty() && maybeReportException()) return; + if (mAllAnswers.isEmpty() && maybeReportError()) return; // TODO: Do RFC6724 sort. - mUserCallback.onAnswer(mAllAnswers); + mUserCallback.onAnswer(mAllAnswers, mRcode); } @Override - public void onAnswer(@NonNull List answer) { - mAllAnswers.addAll(answer); + public void onAnswer(@NonNull byte[] answer, int rcode) { + // If at least one query succeeded, return an rcode of 0. + // Otherwise, arbitrarily return the first rcode received. + if (mReceivedAnswerCount == 0 || rcode == 0) { + mRcode = rcode; + } + try { + mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses()); + } catch (ParseException e) { + mDnsException = new DnsException(ERROR_PARSE, e); + } maybeReportAnswer(); } @Override - public void onParseException(@NonNull ParseException e) { - mParseException = e; - maybeReportAnswer(); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - mErrnoException = e; + public void onError(@NonNull DnsException error) { + mDnsException = error; maybeReportAnswer(); } } /** - * Send a DNS query with the specified name, get back a set of InetAddresses asynchronously. - * The answer will be provided asynchronously through the provided - * {@link InetAddressAnswerCallback}. + * Send a DNS query with the specified name on a network with both IPv4 and IPv6, + * get back a set of InetAddresses asynchronously. + * + * This method will examine the connection ability on given network, and query IPv4 + * and IPv6 if connection is available. + * + * If at least one query succeeded with valid answer, rcode will be 0 + * + * The answer will be provided asynchronously through the provided {@link Callback}. * * @param network {@link Network} specifying which network to query on. * {@code null} for query on default network. @@ -341,13 +324,13 @@ public final class DnsResolver { * @param executor The {@link Executor} that the callback should be executed on. * @param cancellationSignal used by the caller to signal if the query should be * cancelled. May be {@code null}. - * @param callback an {@link InetAddressAnswerCallback} which will be called to notify the + * @param callback a {@link Callback} which will be called to notify the * caller of the result of dns query. */ public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags, @NonNull @CallbackExecutor Executor executor, @Nullable CancellationSignal cancellationSignal, - @NonNull InetAddressAnswerCallback callback) { + @NonNull Callback> callback) { if (cancellationSignal != null && cancellationSignal.isCanceled()) { return; } @@ -365,9 +348,7 @@ public final class DnsResolver { v6fd = resNetworkQuery((network != null ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags); } catch (ErrnoException e) { - executor.execute(() -> { - callback.onQueryException(e); - }); + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; } queryCount++; @@ -377,7 +358,9 @@ public final class DnsResolver { // Avoiding gateways drop packets if queries are sent too close together try { Thread.sleep(SLEEP_TIME_MS); - } catch (InterruptedException ex) { } + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } if (queryIpv4) { try { @@ -385,9 +368,7 @@ public final class DnsResolver { ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags); } catch (ErrnoException e) { if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid. - executor.execute(() -> { - callback.onQueryException(e); - }); + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; } queryCount++; @@ -413,34 +394,89 @@ public final class DnsResolver { } } - private void registerFDListener(@NonNull Executor executor, - @NonNull FileDescriptor queryfd, @NonNull AnswerCallback answerCallback, + /** + * Send a DNS query with the specified name and query type, get back a set of + * InetAddresses asynchronously. + * + * The answer will be provided asynchronously through the provided {@link Callback}. + * + * @param network {@link Network} specifying which network to query on. + * {@code null} for query on default network. + * @param domain domain name to query + * @param nsType dns resource record (RR) type as one of the TYPE_* constants + * @param flags flags as a combination of the FLAGS_* constants + * @param executor The {@link Executor} that the callback should be executed on. + * @param cancellationSignal used by the caller to signal if the query should be + * cancelled. May be {@code null}. + * @param callback a {@link Callback} which will be called to notify the caller + * of the result of dns query. + */ + public void query(@Nullable Network network, @NonNull String domain, + @QueryType int nsType, @QueryFlag int flags, + @NonNull @CallbackExecutor Executor executor, + @Nullable CancellationSignal cancellationSignal, + @NonNull Callback> callback) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } + final Object lock = new Object(); + final FileDescriptor queryfd; + try { + queryfd = resNetworkQuery((network != null + ? network.netId : NETID_UNSET), domain, CLASS_IN, nsType, flags); + } catch (ErrnoException e) { + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); + return; + } + final InetAddressAnswerAccumulator accumulator = + new InetAddressAnswerAccumulator(1, callback); + synchronized (lock) { + registerFDListener(executor, queryfd, accumulator, cancellationSignal, lock); + if (cancellationSignal == null) return; + addCancellationSignal(cancellationSignal, queryfd, lock); + } + } + + /** + * Class to retrieve DNS response + * + * @hide + */ + public static final class DnsResponse { + public final @NonNull byte[] answerbuf; + public final int rcode; + public DnsResponse(@NonNull byte[] answerbuf, int rcode) { + this.answerbuf = answerbuf; + this.rcode = rcode; + } + } + + private void registerFDListener(@NonNull Executor executor, + @NonNull FileDescriptor queryfd, @NonNull Callback answerCallback, @Nullable CancellationSignal cancellationSignal, @NonNull Object lock) { Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener( queryfd, FD_EVENTS, (fd, events) -> { executor.execute(() -> { + DnsResponse resp = null; + ErrnoException exception = null; synchronized (lock) { if (cancellationSignal != null && cancellationSignal.isCanceled()) { return; } - byte[] answerbuf = null; try { - answerbuf = resNetworkResult(fd); // Closes fd, marks it invalid. + resp = resNetworkResult(fd); // Closes fd, marks it invalid. } catch (ErrnoException e) { Log.e(TAG, "resNetworkResult:" + e.toString()); - answerCallback.onQueryException(e); - return; - } - - try { - answerCallback.onAnswer( - answerCallback.parser.parse(answerbuf)); - } catch (ParseException e) { - answerCallback.onParseException(e); + exception = e; } } + if (exception != null) { + answerCallback.onError(new DnsException(ERROR_SYSTEM, exception)); + return; + } + answerCallback.onAnswer(resp.answerbuf, resp.rcode); }); // Unregister this fd listener return 0; diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index db87c97e4f..c06a13269d 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -145,9 +145,10 @@ public class NetworkUtils { /** * DNS resolver series jni method. * Read a result for the query associated with the {@code fd}. - * @return a byte array containing blob answer + * @return DnsResponse containing blob answer and rcode */ - public static native byte[] resNetworkResult(FileDescriptor fd) throws ErrnoException; + public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd) + throws ErrnoException; /** * DNS resolver series jni method. diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index dd754f35bb..28c59db6b9 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -270,7 +270,7 @@ static jobject android_net_utils_resNetworkSend(JNIEnv *env, jobject thiz, jint return jniCreateFileDescriptor(env, fd); } -static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) { +static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) { int fd = jniGetFDFromFileDescriptor(env, javaFd); int rcode; std::vector buf(MAXPACKETSIZE, 0); @@ -291,7 +291,10 @@ static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, reinterpret_cast(buf.data())); } - return answer; + jclass class_DnsResponse = env->FindClass("android/net/DnsResolver$DnsResponse"); + jmethodID ctor = env->GetMethodID(class_DnsResponse, "", "([BI)V"); + + return env->NewObject(class_DnsResponse, ctor, answer, rcode); } static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) { @@ -354,7 +357,7 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket }, { "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend }, { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery }, - { "resNetworkResult", "(Ljava/io/FileDescriptor;)[B", (void*) android_net_utils_resNetworkResult }, + { "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult }, { "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel }, }; From e01a8ccfd74b3398c10123ad780ea4a6e6d2c718 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 9 Apr 2019 11:16:56 +0900 Subject: [PATCH 049/130] Move TrafficStats tags for the network stack constants As per API council feedback, these constants should live in a place that is private to the network stack, only with a range defined in system API. Bug: 129433383 Test: m Change-Id: I84a90f84a9af6fef4667ee4d512ebd0413222086 (cherry picked from commit 79a6330650ca04bd7a08afbd63f8016a3b30bc72) --- .../com/android/server/connectivity/NetworkDiagnostics.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java index 948c690956..a1a8e355dc 100644 --- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java +++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java @@ -33,6 +33,7 @@ import android.text.TextUtils; import android.util.Pair; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.TrafficStatsConstants; import libcore.io.IoUtils; @@ -381,7 +382,8 @@ public class NetworkDiagnostics { protected void setupSocket( int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort) throws ErrnoException, IOException { - final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE); + final int oldTag = TrafficStats.getAndSetThreadStatsTag( + TrafficStatsConstants.TAG_SYSTEM_PROBE); try { mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol); } finally { From 9b4ab0507069d53bbb5b7e6b7d6aacac3018ccef Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Fri, 5 Apr 2019 14:14:55 -0700 Subject: [PATCH 050/130] Add smoke test for jni library Since the Framework net test require jni library libnetworkstatsfactorytestjni, but the test fails to load that library unless *all* the dependencies of that library are explicitly listed in jni_libs, whenever any of the dependencies changes the framework net test will start failing and it might not be catched since the change might not related to frameworks/base. And this smoke test is aimed to spot those native library changes and it should be stable enough to put in global presubmit. Bug: 124764595 Test: FrameworksNetSmokeTests Change-Id: Id24e7f0558b5643e4ad7393e85f1f0a2bd875615 Merged-In: Id24e7f0558b5643e4ad7393e85f1f0a2bd875615 (cherry picked from commit 5f8a630da7d5b308c0824a25f6fc1dd4c7552c9f) --- tests/net/Android.bp | 1 - tests/net/smoketest/Android.bp | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/net/smoketest/Android.bp diff --git a/tests/net/Android.bp b/tests/net/Android.bp index c8ef82ec9a..9098f90fd7 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -49,7 +49,6 @@ java_defaults { "libselinux", "libui", "libutils", - "libvintf", "libvndksupport", "libtinyxml2", "libunwindstack", diff --git a/tests/net/smoketest/Android.bp b/tests/net/smoketest/Android.bp new file mode 100644 index 0000000000..ef1ad2cba8 --- /dev/null +++ b/tests/net/smoketest/Android.bp @@ -0,0 +1,17 @@ +// This test exists only because the jni_libs list for these tests is difficult to +// maintain: the test itself only depends on libnetworkstatsfactorytestjni, but the test +// fails to load that library unless *all* the dependencies of that library are explicitly +// listed in jni_libs. This means that whenever any of the dependencies changes the test +// starts failing and breaking presubmits in frameworks/base. We cannot easily put +// FrameworksNetTests into global presubmit because they are at times flaky, but this +// test is effectively empty beyond validating that the libraries load correctly, and +// thus should be stable enough to put in global presubmit. +// +// TODO: remove this hack when there is a better solution for jni_libs that includes +// dependent libraries. +android_test { + name: "FrameworksNetSmokeTests", + defaults: ["FrameworksNetTests-jni-defaults"], + srcs: ["java/SmokeTest.java"], + test_suites: ["device-tests"], +} From 6fb1669b653834c930b34ab87bc63a4dea8bf31c Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 9 Apr 2019 15:46:21 +0900 Subject: [PATCH 051/130] Restrict access to dangerous methods to <= P Test: make Fixes: 130143562 Change-Id: I1a6a472f83cf00a1ab174a9c5e67d3e9357a0c45 Merged-In: I95107f7b628eecb54e9f4411785186b668e9f3d8 Merged-In: I890030580fdad45c3f8589bf6adbe5798d578cfe (cherry picked from commit 0bb53dbb64bbc937a23e1dc7641c8988a6d11d64) --- core/java/android/net/ConnectivityManager.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2906710b06..0e10de8c4e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -510,7 +510,7 @@ public class ConnectivityManager { * The absence of a connection type. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static final int TYPE_NONE = -1; /** @@ -627,7 +627,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static final int TYPE_MOBILE_FOTA = 10; /** @@ -645,7 +645,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static final int TYPE_MOBILE_CBS = 12; /** @@ -655,7 +655,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static final int TYPE_WIFI_P2P = 13; /** @@ -674,7 +674,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static final int TYPE_MOBILE_EMERGENCY = 15; /** @@ -775,7 +775,7 @@ public class ConnectivityManager { */ public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private final IConnectivityManager mService; /** * A kludge to facilitate static access where a Context pointer isn't available, like in the @@ -867,7 +867,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static boolean isNetworkTypeMobile(int networkType) { switch (networkType) { case TYPE_MOBILE: @@ -1304,7 +1304,7 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public LinkProperties getLinkProperties(int networkType) { try { return mService.getLinkPropertiesForType(networkType); @@ -3042,7 +3042,7 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public boolean isNetworkSupported(int networkType) { try { return mService.isNetworkSupported(networkType); From 830600090c6eb7531840a63d4a3b9883791a907d Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 16 Apr 2019 02:37:43 -0700 Subject: [PATCH 052/130] Fix DnsResolver API could not bypass private DNS correctly Bug: 130594022 Test: atest DnsResolverTest Merged-In: Ic9e078f8acf7688850dfe31f15ed065739ad5281 (cherry picked from commit c21eb1fb31dff7b05aabbbc2f45caf587095abc3) Change-Id: I1788157c784b0ec124bd7d78ba90278b5501d0d4 --- core/java/android/net/DnsResolver.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java index b6c4fe2de4..68826cbeb8 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -197,7 +197,7 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkSend((network != null - ? network.netId : NETID_UNSET), query, query.length, flags); + ? network.getNetIdForResolv() : NETID_UNSET), query, query.length, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -238,7 +238,7 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags); + ? network.getNetIdForResolv() : NETID_UNSET), domain, nsClass, nsType, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -346,7 +346,8 @@ public final class DnsResolver { if (queryIpv6) { try { v6fd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags); + ? network.getNetIdForResolv() : NETID_UNSET), + domain, CLASS_IN, TYPE_AAAA, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -365,7 +366,8 @@ public final class DnsResolver { if (queryIpv4) { try { v4fd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags); + ? network.getNetIdForResolv() : NETID_UNSET), + domain, CLASS_IN, TYPE_A, flags); } catch (ErrnoException e) { if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid. executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); @@ -423,7 +425,7 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, nsType, flags); + ? network.getNetIdForResolv() : NETID_UNSET), domain, CLASS_IN, nsType, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; From cd616ebc950f5a4526d890096cf74a584b053c3c Mon Sep 17 00:00:00 2001 From: Wayne Ma Date: Wed, 17 Apr 2019 08:03:59 -0700 Subject: [PATCH 053/130] Backwards-incompatible resolv module API change for making setResolverConfiguration take a parcelable. Test: built, flashed, booted atest FrameworksNetTests Bug: 130788363 Change-Id: I3b4e8672f5273c3baa9378025bfaef2e6514df64 Merged-In: I6dc9029af0df0d3b391210bd315516bdf1b5e4c9 (cherry picked from commit 9e9fda7558a924feb86869fca7dc7fd7dd01a78c) --- .../server/connectivity/DnsManager.java | 39 +++++--- .../server/ConnectivityServiceTest.java | 93 +++++++++---------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index 1913635f80..e33392d359 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -34,6 +34,7 @@ import android.net.IDnsResolver; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkUtils; +import android.net.ResolverParamsParcel; import android.net.Uri; import android.net.shared.PrivateDnsConfig; import android.os.Binder; @@ -311,11 +312,9 @@ public class DnsManager { public void setDnsConfigurationForNetwork( int netId, LinkProperties lp, boolean isDefaultNetwork) { - final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers()); - final String[] domainStrs = getDomainStrings(lp.getDomains()); updateParametersSettings(); - final int[] params = { mSampleValidity, mSuccessThreshold, mMinSamples, mMaxSamples }; + final ResolverParamsParcel paramsParcel = new ResolverParamsParcel(); // We only use the PrivateDnsConfig data pushed to this class instance // from ConnectivityService because it works in coordination with @@ -329,34 +328,44 @@ public class DnsManager { final boolean useTls = privateDnsCfg.useTls; final boolean strictMode = privateDnsCfg.inStrictMode(); - final String tlsHostname = strictMode ? privateDnsCfg.hostname : ""; - final String[] tlsServers = + paramsParcel.netId = netId; + paramsParcel.sampleValiditySeconds = mSampleValidity; + paramsParcel.successThreshold = mSuccessThreshold; + paramsParcel.minSamples = mMinSamples; + paramsParcel.maxSamples = mMaxSamples; + paramsParcel.servers = NetworkUtils.makeStrings(lp.getDnsServers()); + paramsParcel.domains = getDomainStrings(lp.getDomains()); + paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : ""; + paramsParcel.tlsServers = strictMode ? NetworkUtils.makeStrings( Arrays.stream(privateDnsCfg.ips) .filter((ip) -> lp.isReachable(ip)) .collect(Collectors.toList())) - : useTls ? assignedServers // Opportunistic + : useTls ? paramsParcel.servers // Opportunistic : new String[0]; // Off - + paramsParcel.tlsFingerprints = new String[0]; // Prepare to track the validation status of the DNS servers in the // resolver config when private DNS is in opportunistic or strict mode. if (useTls) { if (!mPrivateDnsValidationMap.containsKey(netId)) { mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses()); } - mPrivateDnsValidationMap.get(netId).updateTrackedDnses(tlsServers, tlsHostname); + mPrivateDnsValidationMap.get(netId).updateTrackedDnses(paramsParcel.tlsServers, + paramsParcel.tlsName); } else { mPrivateDnsValidationMap.remove(netId); } - Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)", - netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs), - Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers))); - final String[] tlsFingerprints = new String[0]; + Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, " + + "%d, %d, %s, %s)", paramsParcel.netId, Arrays.toString(paramsParcel.servers), + Arrays.toString(paramsParcel.domains), paramsParcel.sampleValiditySeconds, + paramsParcel.successThreshold, paramsParcel.minSamples, + paramsParcel.maxSamples, paramsParcel.baseTimeoutMsec, + paramsParcel.retryCount, paramsParcel.tlsName, + Arrays.toString(paramsParcel.tlsServers))); + try { - mDnsResolver.setResolverConfiguration( - netId, assignedServers, domainStrs, params, - tlsHostname, tlsServers, tlsFingerprints); + mDnsResolver.setResolverConfiguration(paramsParcel); } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Error setting DNS configuration: " + e); return; diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 44380cce1c..5f08a347ee 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -131,6 +131,7 @@ import android.net.NetworkStackClient; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.ProxyInfo; +import android.net.ResolverParamsParcel; import android.net.RouteInfo; import android.net.SocketKeepalive; import android.net.UidRange; @@ -262,7 +263,8 @@ public class ConnectivityServiceTest { @Mock INetd mMockNetd; @Mock NetworkStackClient mNetworkStack; - private ArgumentCaptor mStringArrayCaptor = ArgumentCaptor.forClass(String[].class); + private ArgumentCaptor mResolverParamsParcelCaptor = + ArgumentCaptor.forClass(ResolverParamsParcel.class); // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods // do not go through ConnectivityService but talk to netd directly, so they don't automatically @@ -4819,16 +4821,13 @@ public class ConnectivityServiceTest { @Test public void testBasicDnsConfigurationPushed() throws Exception { setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); - ArgumentCaptor tlsServers = ArgumentCaptor.forClass(String[].class); // Clear any interactions that occur as a result of CS starting up. reset(mMockDnsResolver); mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); waitForIdle(); - verify(mMockDnsResolver, never()).setResolverConfiguration( - anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), - eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + verify(mMockDnsResolver, never()).setResolverConfiguration(any()); verifyNoMoreInteractions(mMockDnsResolver); final LinkProperties cellLp = new LinkProperties(); @@ -4846,35 +4845,33 @@ public class ConnectivityServiceTest { mCellNetworkAgent.connect(false); waitForIdle(); // CS tells netd about the empty DNS config for this network. - verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), - eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any()); reset(mMockDnsResolver); cellLp.addDnsServer(InetAddress.getByName("2001:db8::1")); mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); - assertEquals(1, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1")); + mResolverParamsParcelCaptor.capture()); + ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(1, resolvrParams.servers.length); + assertTrue(ArrayUtils.contains(resolvrParams.servers, "2001:db8::1")); // Opportunistic mode. - assertTrue(ArrayUtils.contains(tlsServers.getValue(), "2001:db8::1")); + assertTrue(ArrayUtils.contains(resolvrParams.tlsServers, "2001:db8::1")); reset(mMockDnsResolver); cellLp.addDnsServer(InetAddress.getByName("192.0.2.1")); mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); - assertEquals(2, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + mResolverParamsParcelCaptor.capture()); + resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(2, resolvrParams.servers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.servers, new String[]{"2001:db8::1", "192.0.2.1"})); // Opportunistic mode. - assertEquals(2, tlsServers.getValue().length); - assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), + assertEquals(2, resolvrParams.tlsServers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers, new String[]{"2001:db8::1", "192.0.2.1"})); reset(mMockDnsResolver); @@ -4887,18 +4884,16 @@ public class ConnectivityServiceTest { waitForIdle(); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(TLS_SPECIFIER), eq(TLS_SERVERS), eq(EMPTY_STRING_ARRAY)); - assertEquals(2, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + mResolverParamsParcelCaptor.capture()); + resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(2, resolvrParams.servers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.servers, new String[]{"2001:db8::1", "192.0.2.1"})); reset(mMockDnsResolver); } @Test public void testPrivateDnsSettingsChange() throws Exception { - ArgumentCaptor tlsServers = ArgumentCaptor.forClass(String[].class); - // Clear any interactions that occur as a result of CS starting up. reset(mMockDnsResolver); @@ -4913,9 +4908,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); waitForIdle(); // CS tells netd about the empty DNS config for this network. - verify(mMockDnsResolver, never()).setResolverConfiguration( - anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), - eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + verify(mMockDnsResolver, never()).setResolverConfiguration(any()); verifyNoMoreInteractions(mMockDnsResolver); final LinkProperties cellLp = new LinkProperties(); @@ -4936,14 +4929,14 @@ public class ConnectivityServiceTest { mCellNetworkAgent.connect(false); waitForIdle(); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); - assertEquals(2, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + mResolverParamsParcelCaptor.capture()); + ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(2, resolvrParams.tlsServers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers, new String[]{"2001:db8::1", "192.0.2.1"})); // Opportunistic mode. - assertEquals(2, tlsServers.getValue().length); - assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), + assertEquals(2, resolvrParams.tlsServers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers, new String[]{"2001:db8::1", "192.0.2.1"})); reset(mMockDnsResolver); cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); @@ -4958,23 +4951,23 @@ public class ConnectivityServiceTest { setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com"); verify(mMockDnsResolver, times(1)).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); - assertEquals(2, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + mResolverParamsParcelCaptor.capture()); + resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(2, resolvrParams.servers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.servers, new String[]{"2001:db8::1", "192.0.2.1"})); reset(mMockDnsResolver); cellNetworkCallback.assertNoCallback(); setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com"); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - anyInt(), mStringArrayCaptor.capture(), any(), any(), - eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY)); - assertEquals(2, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(), + mResolverParamsParcelCaptor.capture()); + resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(2, resolvrParams.servers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.servers, new String[]{"2001:db8::1", "192.0.2.1"})); - assertEquals(2, tlsServers.getValue().length); - assertTrue(ArrayUtils.containsAll(tlsServers.getValue(), + assertEquals(2, resolvrParams.tlsServers.length); + assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers, new String[]{"2001:db8::1", "192.0.2.1"})); reset(mMockDnsResolver); cellNetworkCallback.assertNoCallback(); @@ -5826,9 +5819,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(cellLp); networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent); verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId); - verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( - eq(cellNetId), eq(EMPTY_STRING_ARRAY), any(), any(), - eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); + verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any()); verifyNoMoreInteractions(mMockNetd); verifyNoMoreInteractions(mMockDnsResolver); @@ -5871,10 +5862,10 @@ public class ConnectivityServiceTest { assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0)); verify(mMockDnsResolver, times(1)).setResolverConfiguration( - eq(cellNetId), mStringArrayCaptor.capture(), any(), any(), - eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY)); - assertEquals(1, mStringArrayCaptor.getValue().length); - assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "8.8.8.8")); + mResolverParamsParcelCaptor.capture()); + ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue(); + assertEquals(1, resolvrParams.servers.length); + assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8")); // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked // linkproperties are cleaned up. From de9b8a9d7e1544626afabc5d11ad5a02a6da5ba5 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 10 Apr 2019 23:07:55 +0900 Subject: [PATCH 054/130] Make LegacyTypeTracker testable ...and add basic trivial tests for it. Test: this, and ConnectivityServiceTest Bug: 62650382 Change-Id: Ie7ca938e6f66f1b15feb6ed93afa0aebb20884ae --- .../android/server/ConnectivityService.java | 34 ++++--- tests/net/Android.bp | 2 +- .../android/server/LegacyTypeTrackerTest.kt | 92 +++++++++++++++++++ 3 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 tests/net/java/com/android/server/LegacyTypeTrackerTest.kt diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index e4c39ccd62..6c3a169b85 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -47,6 +47,7 @@ import static android.system.OsConstants.IPPROTO_UDP; import static com.android.internal.util.Preconditions.checkNotNull; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.BroadcastOptions; import android.app.NotificationManager; @@ -632,7 +633,8 @@ public class ConnectivityService extends IConnectivityManager.Stub * the first network for a given type changes, or if the default network * changes. */ - private class LegacyTypeTracker { + @VisibleForTesting + static class LegacyTypeTracker { private static final boolean DBG = true; private static final boolean VDBG = false; @@ -658,10 +660,12 @@ public class ConnectivityService extends IConnectivityManager.Stub * - dump is thread-safe with respect to concurrent add and remove calls. */ private final ArrayList mTypeLists[]; + @NonNull + private final ConnectivityService mService; - public LegacyTypeTracker() { - mTypeLists = (ArrayList[]) - new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1]; + LegacyTypeTracker(@NonNull ConnectivityService service) { + mService = service; + mTypeLists = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1]; } public void addSupportedType(int type) { @@ -710,10 +714,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } // Send a broadcast if this is the first network of its type or if it's the default. - final boolean isDefaultNetwork = isDefaultNetwork(nai); + final boolean isDefaultNetwork = mService.isDefaultNetwork(nai); if ((list.size() == 1) || isDefaultNetwork) { maybeLogBroadcast(nai, DetailedState.CONNECTED, type, isDefaultNetwork); - sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type); + mService.sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type); } } @@ -735,15 +739,15 @@ public class ConnectivityService extends IConnectivityManager.Stub if (wasFirstNetwork || wasDefault) { maybeLogBroadcast(nai, state, type, wasDefault); - sendLegacyNetworkBroadcast(nai, state, type); + mService.sendLegacyNetworkBroadcast(nai, state, type); } if (!list.isEmpty() && wasFirstNetwork) { if (DBG) log("Other network available for type " + type + ", sending connected broadcast"); final NetworkAgentInfo replacement = list.get(0); - maybeLogBroadcast(replacement, state, type, isDefaultNetwork(replacement)); - sendLegacyNetworkBroadcast(replacement, state, type); + maybeLogBroadcast(replacement, state, type, mService.isDefaultNetwork(replacement)); + mService.sendLegacyNetworkBroadcast(replacement, state, type); } } @@ -758,7 +762,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // send out another legacy broadcast - currently only used for suspend/unsuspend // toggle public void update(NetworkAgentInfo nai) { - final boolean isDefault = isDefaultNetwork(nai); + final boolean isDefault = mService.isDefaultNetwork(nai); final DetailedState state = nai.networkInfo.getDetailedState(); for (int type = 0; type < mTypeLists.length; type++) { final ArrayList list = mTypeLists[type]; @@ -766,7 +770,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final boolean isFirst = contains && (nai == list.get(0)); if (isFirst || contains && isDefault) { maybeLogBroadcast(nai, state, type, isDefault); - sendLegacyNetworkBroadcast(nai, state, type); + mService.sendLegacyNetworkBroadcast(nai, state, type); } } } @@ -802,7 +806,7 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.println(); } } - private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(); + private final LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(this); /** * Helper class which parses out priority arguments and dumps sections according to their @@ -5357,7 +5361,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private boolean isDefaultNetwork(NetworkAgentInfo nai) { + @VisibleForTesting + protected boolean isDefaultNetwork(NetworkAgentInfo nai) { return nai == getDefaultNetwork(); } @@ -6565,7 +6570,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) { + @VisibleForTesting + protected void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) { // The NetworkInfo we actually send out has no bearing on the real // state of affairs. For example, if the default connection is mobile, // and a request for HIPRI has just gone away, we need to pretend that diff --git a/tests/net/Android.bp b/tests/net/Android.bp index c8ef82ec9a..3ff862c323 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -64,7 +64,7 @@ java_defaults { android_test { name: "FrameworksNetTests", defaults: ["FrameworksNetTests-jni-defaults"], - srcs: ["java/**/*.java"], + srcs: ["java/**/*.java", "java/**/*.kt"], platform_apis: true, test_suites: ["device-tests"], certificate: "platform", diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt new file mode 100644 index 0000000000..d983b6544b --- /dev/null +++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2019 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 android.net.ConnectivityManager.TYPE_ETHERNET +import android.net.ConnectivityManager.TYPE_MOBILE +import android.net.ConnectivityManager.TYPE_WIFI +import android.net.ConnectivityManager.TYPE_WIMAX +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.server.ConnectivityService.LegacyTypeTracker +import com.android.server.connectivity.NetworkAgentInfo +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull +import org.junit.Assert.assertSame +import org.junit.Assert.assertTrue +import org.junit.Assert.fail +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock + +const val UNSUPPORTED_TYPE = TYPE_WIMAX + +@RunWith(AndroidJUnit4::class) +@SmallTest +class LegacyTypeTrackerTest { + private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET) + + private val mMockService = mock(ConnectivityService::class.java).apply { + doReturn(false).`when`(this).isDefaultNetwork(any()) + } + private val mTracker = LegacyTypeTracker(mMockService).apply { + supportedTypes.forEach { + addSupportedType(it) + } + } + + @Test + fun testSupportedTypes() { + try { + mTracker.addSupportedType(supportedTypes[0]) + fail("Expected IllegalStateException") + } catch (expected: IllegalStateException) {} + supportedTypes.forEach { + assertTrue(mTracker.isTypeSupported(it)) + } + assertFalse(mTracker.isTypeSupported(UNSUPPORTED_TYPE)) + } + + @Test + fun testAddNetwork() { + val mobileNai = mock(NetworkAgentInfo::class.java) + val wifiNai = mock(NetworkAgentInfo::class.java) + mTracker.add(TYPE_MOBILE, mobileNai) + mTracker.add(TYPE_WIFI, wifiNai) + assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai) + assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai) + // Make sure adding a second NAI does not change the results. + val secondMobileNai = mock(NetworkAgentInfo::class.java) + mTracker.add(TYPE_MOBILE, secondMobileNai) + assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai) + assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai) + // Make sure removing a network that wasn't added for this type is a no-op. + mTracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */) + assertSame(mTracker.getNetworkForType(TYPE_MOBILE), mobileNai) + assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai) + // Remove the top network for mobile and make sure the second one becomes the network + // of record for this type. + mTracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */) + assertSame(mTracker.getNetworkForType(TYPE_MOBILE), secondMobileNai) + assertSame(mTracker.getNetworkForType(TYPE_WIFI), wifiNai) + // Make sure adding a network for an unsupported type does not register it. + mTracker.add(UNSUPPORTED_TYPE, mobileNai) + assertNull(mTracker.getNetworkForType(UNSUPPORTED_TYPE)) + } +} From e6a296dca57b2f4d0de974bd8006c675f9a481da Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 11 Apr 2019 14:09:07 +0900 Subject: [PATCH 055/130] Fix an argument to the legacy broadcast Test: new test for this Fixes: 62650382 Change-Id: I918b8271d3c3c058553ca888cb54cd36a6efba66 Merged-In: I0fc408d546ae9d72b7dd9415e502252b484d4329 Merged-In: I9282930106d1eee3274d9e5c4e89de60e929a0e6 --- .../android/server/ConnectivityService.java | 11 +++++----- .../android/server/LegacyTypeTrackerTest.kt | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6c3a169b85..943a9c92c9 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -735,19 +735,18 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - final DetailedState state = DetailedState.DISCONNECTED; - if (wasFirstNetwork || wasDefault) { - maybeLogBroadcast(nai, state, type, wasDefault); - mService.sendLegacyNetworkBroadcast(nai, state, type); + maybeLogBroadcast(nai, DetailedState.DISCONNECTED, type, wasDefault); + mService.sendLegacyNetworkBroadcast(nai, DetailedState.DISCONNECTED, type); } if (!list.isEmpty() && wasFirstNetwork) { if (DBG) log("Other network available for type " + type + ", sending connected broadcast"); final NetworkAgentInfo replacement = list.get(0); - maybeLogBroadcast(replacement, state, type, mService.isDefaultNetwork(replacement)); - mService.sendLegacyNetworkBroadcast(replacement, state, type); + maybeLogBroadcast(replacement, DetailedState.CONNECTED, type, + mService.isDefaultNetwork(replacement)); + mService.sendLegacyNetworkBroadcast(replacement, DetailedState.CONNECTED, type); } } diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt index d983b6544b..f045369459 100644 --- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt +++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt @@ -20,6 +20,8 @@ import android.net.ConnectivityManager.TYPE_ETHERNET import android.net.ConnectivityManager.TYPE_MOBILE import android.net.ConnectivityManager.TYPE_WIFI import android.net.ConnectivityManager.TYPE_WIMAX +import android.net.NetworkInfo.DetailedState.CONNECTED +import android.net.NetworkInfo.DetailedState.DISCONNECTED import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 import com.android.server.ConnectivityService.LegacyTypeTracker @@ -32,8 +34,12 @@ import org.junit.Assert.fail import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.reset +import org.mockito.Mockito.verify const val UNSUPPORTED_TYPE = TYPE_WIMAX @@ -89,4 +95,20 @@ class LegacyTypeTrackerTest { mTracker.add(UNSUPPORTED_TYPE, mobileNai) assertNull(mTracker.getNetworkForType(UNSUPPORTED_TYPE)) } + + @Test + fun testBroadcastOnDisconnect() { + val mobileNai1 = mock(NetworkAgentInfo::class.java) + val mobileNai2 = mock(NetworkAgentInfo::class.java) + doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1) + mTracker.add(TYPE_MOBILE, mobileNai1) + verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE) + reset(mMockService) + doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2) + mTracker.add(TYPE_MOBILE, mobileNai2) + verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt()) + mTracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */) + verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, DISCONNECTED, TYPE_MOBILE) + verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE) + } } From 7266129a6c77cacd4f20e550620e2970624f0e93 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 23 Apr 2019 01:55:01 -0700 Subject: [PATCH 056/130] Freeze the networkstack-aidl-interfaces interface This freezes the interface as of the latest beta build, not the tip of tree. IIpClient#setL2KeyAndGroupHint is not in the frozen definition in particular. Generated with: m networkstack-aidl-interfaces-freeze-api \ ipmemorystore-aidl-interfaces-freeze-api Test: flashed, booted, WiFi and captive portal working Bug: 128803828 Change-Id: Ideabe73fc93bbefca2d624ee9ca190cf31419424 Merged-In: Ideabe73fc93bbefca2d624ee9ca190cf31419424 (cherry picked from commit 9b89cdaaf401a6b77e160807039c06e537fa600a) --- .../core/java/com/android/server/ConnectivityService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 943a9c92c9..ee8bb0524d 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2811,6 +2811,11 @@ public class ConnectivityService extends IConnectivityManager.Stub EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE, mNai.network.netId)); } + + @Override + public int getInterfaceVersion() { + return this.VERSION; + } } private boolean networkRequiresValidation(NetworkAgentInfo nai) { From dc587d75e1332ef23a1e96dceb8f88f097b5becd Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Thu, 11 Apr 2019 11:45:43 -0700 Subject: [PATCH 057/130] Block incoming non-VPN packets to apps under fully-routed VPN When a fully-routed VPN is running, we want to prevent normal apps under the VPN from receiving packets originating from any local non-VPN interfaces. This is achieved by using eBPF to create a per-UID input interface whitelist and populate the whitelist such that all non-bypassable apps under a VPN can only receive packets from the VPN's TUN interface (and loopback implicitly) This is the framework part of the change that build the whitelist. The whitelist needs to be updated in the following cases: * When a VPN is connected and disconnected This will cover the change to allowBypass bit, since that can't be changed without reconnecting. * When a VPN's NetworkCapabilites is changed (whitelist/blacklist app changes) * When a new app is installed * When an existing app is removed * When a VPN becomes fully-routed or is no longer fully-routed New user/profile creation will automatically result in a whitelist app change transition so it doesn't need to be handled specially here. Due to the limitation of the kernel IPSec interacting with eBPF (sk_buf->ifindex does not point to the virtual tunnel interface for kernel IPSec), the whitelist will only apply to app VPNs but not legacy VPN connections, to prevent breaking connectivity with kernel IPSec entirely. Test: atest PermissionMonitorTest Test: atest android.net.RouteInfoTest Test: atest com.android.server.ConnectivityServiceTest Test: atest HostsideVpnTests Bug: 114231106 Merged-In: I5af81bc80dadd086261ba4b1eb706cc873bb7cfa Change-Id: I5af81bc80dadd086261ba4b1eb706cc873bb7cfa (cherry picked from commit 65968ea16bf49f678d4a43c220e1d67393170459) --- .../java/android/net/NetworkCapabilities.java | 5 + core/java/android/net/UidRange.java | 27 +++ .../android/server/ConnectivityService.java | 112 ++++++++- .../connectivity/PermissionMonitor.java | 212 ++++++++++++++++-- tests/net/java/android/net/RouteInfoTest.java | 131 ++++++----- .../server/ConnectivityServiceTest.java | 200 ++++++++++++++++- .../connectivity/PermissionMonitorTest.java | 155 +++++++++++-- 7 files changed, 738 insertions(+), 104 deletions(-) diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 02145f2705..3e325b748f 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -822,6 +822,11 @@ public final class NetworkCapabilities implements Parcelable { mEstablishingVpnAppUid = uid; } + /** @hide */ + public int getEstablishingVpnAppUid() { + return mEstablishingVpnAppUid; + } + /** * Value indicating that link bandwidth is unspecified. * @hide diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java index e56f05995c..d75c43ddb3 100644 --- a/core/java/android/net/UidRange.java +++ b/core/java/android/net/UidRange.java @@ -21,6 +21,8 @@ import static android.os.UserHandle.PER_USER_RANGE; import android.os.Parcel; import android.os.Parcelable; +import java.util.Collection; + /** * An inclusive range of UIDs. * @@ -42,10 +44,16 @@ public final class UidRange implements Parcelable { return new UidRange(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1); } + /** Returns the smallest user Id which is contained in this UidRange */ public int getStartUser() { return start / PER_USER_RANGE; } + /** Returns the largest user Id which is contained in this UidRange */ + public int getEndUser() { + return stop / PER_USER_RANGE; + } + public boolean contains(int uid) { return start <= uid && uid <= stop; } @@ -117,4 +125,23 @@ public final class UidRange implements Parcelable { return new UidRange[size]; } }; + + /** + * Returns whether any of the UidRange in the collection contains the specified uid + * + * @param ranges The collection of UidRange to check + * @param uid the uid in question + * @return {@code true} if the uid is contained within the ranges, {@code false} otherwise + * + * @see UidRange#contains(int) + */ + public static boolean containsUid(Collection ranges, int uid) { + if (ranges == null) return false; + for (UidRange range : ranges) { + if (range.contains(uid)) { + return true; + } + } + return false; + } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ee8bb0524d..313c0a867d 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -277,7 +277,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private Tethering mTethering; - private final PermissionMonitor mPermissionMonitor; + @VisibleForTesting + protected final PermissionMonitor mPermissionMonitor; private KeyStore mKeyStore; @@ -832,13 +833,13 @@ public class ConnectivityService extends IConnectivityManager.Stub public ConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager) { this(context, netManager, statsService, policyManager, - getDnsResolver(), new IpConnectivityLog()); + getDnsResolver(), new IpConnectivityLog(), NetdService.getInstance()); } @VisibleForTesting protected ConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager, - IDnsResolver dnsresolver, IpConnectivityLog logger) { + IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd) { if (DBG) log("ConnectivityService starting up"); mSystemProperties = getSystemProperties(); @@ -878,7 +879,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver"); mProxyTracker = makeProxyTracker(); - mNetd = NetdService.getInstance(); + mNetd = netd; mKeyStore = KeyStore.getInstance(); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); @@ -964,7 +965,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mTethering = makeTethering(); - mPermissionMonitor = new PermissionMonitor(mContext, mNMS, mNetd); + mPermissionMonitor = new PermissionMonitor(mContext, mNetd); // Set up the listener for user state for creating user VPNs. // Should run on mHandler to avoid any races. @@ -2446,6 +2447,13 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.println("NetworkStackClient logs:"); pw.increaseIndent(); NetworkStackClient.getInstance().dump(pw); + pw.decreaseIndent(); + + pw.println(); + pw.println("Permission Monitor:"); + pw.increaseIndent(); + mPermissionMonitor.dump(pw); + pw.decreaseIndent(); } private void dumpNetworks(IndentingPrintWriter pw) { @@ -5469,6 +5477,11 @@ public class ConnectivityService extends IConnectivityManager.Stub networkAgent.clatd.fixupLinkProperties(oldLp, newLp); updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities); + + // update filtering rules, need to happen after the interface update so netd knows about the + // new interface (the interface name -> index map becomes initialized) + updateVpnFiltering(newLp, oldLp, networkAgent); + updateMtu(newLp, oldLp); // TODO - figure out what to do for clat // for (LinkProperties lp : newLp.getStackedLinks()) { @@ -5634,6 +5647,37 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void updateVpnFiltering(LinkProperties newLp, LinkProperties oldLp, + NetworkAgentInfo nai) { + final String oldIface = oldLp != null ? oldLp.getInterfaceName() : null; + final String newIface = newLp != null ? newLp.getInterfaceName() : null; + final boolean wasFiltering = requiresVpnIsolation(nai, nai.networkCapabilities, oldLp); + final boolean needsFiltering = requiresVpnIsolation(nai, nai.networkCapabilities, newLp); + + if (!wasFiltering && !needsFiltering) { + // Nothing to do. + return; + } + + if (Objects.equals(oldIface, newIface) && (wasFiltering == needsFiltering)) { + // Nothing changed. + return; + } + + final Set ranges = nai.networkCapabilities.getUids(); + final int vpnAppUid = nai.networkCapabilities.getEstablishingVpnAppUid(); + // TODO: this create a window of opportunity for apps to receive traffic between the time + // when the old rules are removed and the time when new rules are added. To fix this, + // make eBPF support two whitelisted interfaces so here new rules can be added before the + // old rules are being removed. + if (wasFiltering) { + mPermissionMonitor.onVpnUidRangesRemoved(oldIface, ranges, vpnAppUid); + } + if (needsFiltering) { + mPermissionMonitor.onVpnUidRangesAdded(newIface, ranges, vpnAppUid); + } + } + private int getNetworkPermission(NetworkCapabilities nc) { if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { return INetd.PERMISSION_SYSTEM; @@ -5776,6 +5820,34 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + /** + * Returns whether VPN isolation (ingress interface filtering) should be applied on the given + * network. + * + * Ingress interface filtering enforces that all apps under the given network can only receive + * packets from the network's interface (and loopback). This is important for VPNs because + * apps that cannot bypass a fully-routed VPN shouldn't be able to receive packets from any + * non-VPN interfaces. + * + * As a result, this method should return true iff + * 1. the network is an app VPN (not legacy VPN) + * 2. the VPN does not allow bypass + * 3. the VPN is fully-routed + * 4. the VPN interface is non-null + * + * @See INetd#firewallAddUidInterfaceRules + * @See INetd#firewallRemoveUidInterfaceRules + */ + private boolean requiresVpnIsolation(@NonNull NetworkAgentInfo nai, NetworkCapabilities nc, + LinkProperties lp) { + if (nc == null || lp == null) return false; + return nai.isVPN() + && !nai.networkMisc.allowBypass + && nc.getEstablishingVpnAppUid() != Process.SYSTEM_UID + && lp.getInterfaceName() != null + && (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute()); + } + private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc, NetworkCapabilities newNc) { Set prevRanges = null == prevNc ? null : prevNc.getUids(); @@ -5788,6 +5860,12 @@ public class ConnectivityService extends IConnectivityManager.Stub newRanges.removeAll(prevRangesCopy); try { + // When updating the VPN uid routing rules, add the new range first then remove the old + // range. If old range were removed first, there would be a window between the old + // range being removed and the new range being added, during which UIDs contained + // in both ranges are not subject to any VPN routing rules. Adding new range before + // removing old range works because, unlike the filtering rules below, it's possible to + // add duplicate UID routing rules. if (!newRanges.isEmpty()) { final UidRange[] addedRangesArray = new UidRange[newRanges.size()]; newRanges.toArray(addedRangesArray); @@ -5798,9 +5876,31 @@ public class ConnectivityService extends IConnectivityManager.Stub prevRanges.toArray(removedRangesArray); mNMS.removeVpnUidRanges(nai.network.netId, removedRangesArray); } + final boolean wasFiltering = requiresVpnIsolation(nai, prevNc, nai.linkProperties); + final boolean shouldFilter = requiresVpnIsolation(nai, newNc, nai.linkProperties); + final String iface = nai.linkProperties.getInterfaceName(); + // For VPN uid interface filtering, old ranges need to be removed before new ranges can + // be added, due to the range being expanded and stored as invidiual UIDs. For example + // the UIDs might be updated from [0, 99999] to ([0, 10012], [10014, 99999]) which means + // prevRanges = [0, 99999] while newRanges = [0, 10012], [10014, 99999]. If prevRanges + // were added first and then newRanges got removed later, there would be only one uid + // 10013 left. A consequence of removing old ranges before adding new ranges is that + // there is now a window of opportunity when the UIDs are not subject to any filtering. + // Note that this is in contrast with the (more robust) update of VPN routing rules + // above, where the addition of new ranges happens before the removal of old ranges. + // TODO Fix this window by computing an accurate diff on Set, so the old range + // to be removed will never overlap with the new range to be added. + if (wasFiltering && !prevRanges.isEmpty()) { + mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges, + prevNc.getEstablishingVpnAppUid()); + } + if (shouldFilter && !newRanges.isEmpty()) { + mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges, + newNc.getEstablishingVpnAppUid()); + } } catch (Exception e) { // Never crash! - loge("Exception in updateUids: " + e); + loge("Exception in updateUids: ", e); } } diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index b6946023e8..f8582cd792 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -37,22 +37,27 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.UserInfo; import android.net.INetd; +import android.net.UidRange; import android.os.Build; -import android.os.INetworkManagementService; import android.os.RemoteException; +import android.os.ServiceSpecificException; import android.os.UserHandle; import android.os.UserManager; +import android.system.OsConstants; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.SystemConfig; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -60,6 +65,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; + /** * A utility class to inform Netd of UID permisisons. * Does a mass update at boot and then monitors for app install/remove. @@ -73,18 +79,29 @@ public class PermissionMonitor { protected static final Boolean NETWORK = Boolean.FALSE; private static final int VERSION_Q = Build.VERSION_CODES.Q; - private final Context mContext; private final PackageManager mPackageManager; private final UserManager mUserManager; - private final INetworkManagementService mNMS; private final INetd mNetd; // Values are User IDs. + @GuardedBy("this") private final Set mUsers = new HashSet<>(); - // Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission. + // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission. + @GuardedBy("this") private final Map mApps = new HashMap<>(); + // Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges + // for apps under the VPN + @GuardedBy("this") + private final Map> mVpnUidRanges = new HashMap<>(); + + // A set of appIds for apps across all users on the device. We track appIds instead of uids + // directly to reduce its size and also eliminate the need to update this set when user is + // added/removed. + @GuardedBy("this") + private final Set mAllApps = new HashSet<>(); + private class PackageListObserver implements PackageManagerInternal.PackageListObserver { private int getPermissionForUid(int uid) { @@ -118,12 +135,10 @@ public class PermissionMonitor { } } - public PermissionMonitor(Context context, INetworkManagementService nms, INetd netdService) { - mContext = context; + public PermissionMonitor(Context context, INetd netd) { mPackageManager = context.getPackageManager(); - mUserManager = UserManager.get(context); - mNMS = nms; - mNetd = netdService; + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mNetd = netd; } // Intended to be called only once at startup, after the system is ready. Installs a broadcast @@ -151,6 +166,7 @@ public class PermissionMonitor { if (uid < 0) { continue; } + mAllApps.add(UserHandle.getAppId(uid)); boolean isNetwork = hasNetworkPermission(app); boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app); @@ -270,10 +286,11 @@ public class PermissionMonitor { } } - private int[] toIntArray(List list) { + private int[] toIntArray(Collection list) { int[] array = new int[list.size()]; - for (int i = 0; i < list.size(); i++) { - array[i] = list.get(i); + int i = 0; + for (Integer item : list) { + array[i++] = item; } return array; } @@ -289,11 +306,11 @@ public class PermissionMonitor { } try { if (add) { - mNMS.setPermission("NETWORK", toIntArray(network)); - mNMS.setPermission("SYSTEM", toIntArray(system)); + mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network)); + mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system)); } else { - mNMS.clearPermission(toIntArray(network)); - mNMS.clearPermission(toIntArray(system)); + mNetd.networkClearPermissionForUser(toIntArray(network)); + mNetd.networkClearPermissionForUser(toIntArray(system)); } } catch (RemoteException e) { loge("Exception when updating permissions: " + e); @@ -376,6 +393,19 @@ public class PermissionMonitor { apps.put(uid, permission); update(mUsers, apps, true); } + + // If the newly-installed package falls within some VPN's uid range, update Netd with it. + // This needs to happen after the mApps update above, since removeBypassingUids() depends + // on mApps to check if the package can bypass VPN. + for (Map.Entry> vpn : mVpnUidRanges.entrySet()) { + if (UidRange.containsUid(vpn.getValue(), uid)) { + final Set changedUids = new HashSet<>(); + changedUids.add(uid); + removeBypassingUids(changedUids, /* vpnAppUid */ -1); + updateVpnUids(vpn.getKey(), changedUids, true); + } + } + mAllApps.add(UserHandle.getAppId(uid)); } /** @@ -386,8 +416,23 @@ public class PermissionMonitor { * @hide */ public synchronized void onPackageRemoved(int uid) { - Map apps = new HashMap<>(); + // If the newly-removed package falls within some VPN's uid range, update Netd with it. + // This needs to happen before the mApps update below, since removeBypassingUids() depends + // on mApps to check if the package can bypass VPN. + for (Map.Entry> vpn : mVpnUidRanges.entrySet()) { + if (UidRange.containsUid(vpn.getValue(), uid)) { + final Set changedUids = new HashSet<>(); + changedUids.add(uid); + removeBypassingUids(changedUids, /* vpnAppUid */ -1); + updateVpnUids(vpn.getKey(), changedUids, false); + } + } + // If the package has been removed from all users on the device, clear it form mAllApps. + if (mPackageManager.getNameForUid(uid) == null) { + mAllApps.remove(UserHandle.getAppId(uid)); + } + Map apps = new HashMap<>(); Boolean permission = null; String[] packages = mPackageManager.getPackagesForUid(uid); if (packages != null && packages.length > 0) { @@ -442,6 +487,121 @@ public class PermissionMonitor { } } + /** + * Called when a new set of UID ranges are added to an active VPN network + * + * @param iface The active VPN network's interface name + * @param rangesToAdd The new UID ranges to be added to the network + * @param vpnAppUid The uid of the VPN app + */ + public synchronized void onVpnUidRangesAdded(@NonNull String iface, Set rangesToAdd, + int vpnAppUid) { + // Calculate the list of new app uids under the VPN due to the new UID ranges and update + // Netd about them. Because mAllApps only contains appIds instead of uids, the result might + // be an overestimation if an app is not installed on the user on which the VPN is running, + // but that's safe. + final Set changedUids = intersectUids(rangesToAdd, mAllApps); + removeBypassingUids(changedUids, vpnAppUid); + updateVpnUids(iface, changedUids, true); + if (mVpnUidRanges.containsKey(iface)) { + mVpnUidRanges.get(iface).addAll(rangesToAdd); + } else { + mVpnUidRanges.put(iface, new HashSet(rangesToAdd)); + } + } + + /** + * Called when a set of UID ranges are removed from an active VPN network + * + * @param iface The VPN network's interface name + * @param rangesToRemove Existing UID ranges to be removed from the VPN network + * @param vpnAppUid The uid of the VPN app + */ + public synchronized void onVpnUidRangesRemoved(@NonNull String iface, + Set rangesToRemove, int vpnAppUid) { + // Calculate the list of app uids that are no longer under the VPN due to the removed UID + // ranges and update Netd about them. + final Set changedUids = intersectUids(rangesToRemove, mAllApps); + removeBypassingUids(changedUids, vpnAppUid); + updateVpnUids(iface, changedUids, false); + Set existingRanges = mVpnUidRanges.getOrDefault(iface, null); + if (existingRanges == null) { + loge("Attempt to remove unknown vpn uid Range iface = " + iface); + return; + } + existingRanges.removeAll(rangesToRemove); + if (existingRanges.size() == 0) { + mVpnUidRanges.remove(iface); + } + } + + /** + * Compute the intersection of a set of UidRanges and appIds. Returns a set of uids + * that satisfies: + * 1. falls into one of the UidRange + * 2. matches one of the appIds + */ + private Set intersectUids(Set ranges, Set appIds) { + Set result = new HashSet<>(); + for (UidRange range : ranges) { + for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) { + for (int appId : appIds) { + final int uid = UserHandle.getUid(userId, appId); + if (range.contains(uid)) { + result.add(uid); + } + } + } + } + return result; + } + + /** + * Remove all apps which can elect to bypass the VPN from the list of uids + * + * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN + * app itself. + * + * @param uids The list of uids to operate on + * @param vpnAppUid The uid of the VPN app + */ + private void removeBypassingUids(Set uids, int vpnAppUid) { + uids.remove(vpnAppUid); + uids.removeIf(uid -> mApps.getOrDefault(uid, NETWORK) == SYSTEM); + } + + /** + * Update netd about the list of uids that are under an active VPN connection which they cannot + * bypass. + * + * This is to instruct netd to set up appropriate filtering rules for these uids, such that they + * can only receive ingress packets from the VPN's tunnel interface (and loopback). + * + * @param iface the interface name of the active VPN connection + * @param add {@code true} if the uids are to be added to the interface, {@code false} if they + * are to be removed from the interface. + */ + private void updateVpnUids(String iface, Set uids, boolean add) { + if (uids.size() == 0) { + return; + } + try { + if (add) { + mNetd.firewallAddUidInterfaceRules(iface, toIntArray(uids)); + } else { + mNetd.firewallRemoveUidInterfaceRules(toIntArray(uids)); + } + } catch (ServiceSpecificException e) { + // Silently ignore exception when device does not support eBPF, otherwise just log + // the exception and do not crash + if (e.errorCode != OsConstants.EOPNOTSUPP) { + loge("Exception when updating permissions: ", e); + } + } catch (RemoteException e) { + loge("Exception when updating permissions: ", e); + } + } + /** * Called by PackageListObserver when a package is installed/uninstalled. Send the updated * permission information to netd. @@ -528,6 +688,24 @@ public class PermissionMonitor { } } + /** Should only be used by unit tests */ + @VisibleForTesting + public Set getVpnUidRanges(String iface) { + return mVpnUidRanges.get(iface); + } + + /** Dump info to dumpsys */ + public void dump(IndentingPrintWriter pw) { + pw.println("Interface filtering rules:"); + pw.increaseIndent(); + for (Map.Entry> vpn : mVpnUidRanges.entrySet()) { + pw.println("Interface: " + vpn.getKey()); + pw.println("UIDs: " + vpn.getValue().toString()); + pw.println(); + } + pw.decreaseIndent(); + } + private static void log(String s) { if (DBG) { Log.d(TAG, s); diff --git a/tests/net/java/android/net/RouteInfoTest.java b/tests/net/java/android/net/RouteInfoTest.java index 831fefd283..2edbd403b5 100644 --- a/tests/net/java/android/net/RouteInfoTest.java +++ b/tests/net/java/android/net/RouteInfoTest.java @@ -16,15 +16,16 @@ package android.net; -import java.lang.reflect.Method; -import java.net.InetAddress; +import static android.net.RouteInfo.RTN_UNREACHABLE; -import android.net.IpPrefix; -import android.net.RouteInfo; import android.os.Parcel; +import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; -import android.test.suitebuilder.annotation.SmallTest; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; public class RouteInfoTest extends TestCase { @@ -152,67 +153,85 @@ public class RouteInfoTest extends TestCase { } public void testHostAndDefaultRoutes() { - RouteInfo r; + RouteInfo r; - r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0"); - assertFalse(r.isHostRoute()); - assertTrue(r.isDefaultRoute()); - assertTrue(r.isIPv4Default()); - assertFalse(r.isIPv6Default()); + r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0"); + assertFalse(r.isHostRoute()); + assertTrue(r.isDefaultRoute()); + assertTrue(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); - r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0"); - assertFalse(r.isHostRoute()); - assertTrue(r.isDefaultRoute()); - assertFalse(r.isIPv4Default()); - assertTrue(r.isIPv6Default()); + r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0"); + assertFalse(r.isHostRoute()); + assertTrue(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertTrue(r.isIPv6Default()); - r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0"); - assertFalse(r.isHostRoute()); - assertFalse(r.isDefaultRoute()); - assertFalse(r.isIPv4Default()); - assertFalse(r.isIPv6Default()); + r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0"); + assertFalse(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); - r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0"); - assertFalse(r.isHostRoute()); - assertFalse(r.isDefaultRoute()); - assertFalse(r.isIPv4Default()); - assertFalse(r.isIPv6Default()); + r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0"); + assertFalse(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); - r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0"); - assertTrue(r.isHostRoute()); - assertFalse(r.isDefaultRoute()); - assertFalse(r.isIPv4Default()); - assertFalse(r.isIPv6Default()); + r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0"); + assertTrue(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); - r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0"); - assertTrue(r.isHostRoute()); - assertFalse(r.isDefaultRoute()); - assertFalse(r.isIPv4Default()); - assertFalse(r.isIPv6Default()); + r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0"); + assertTrue(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); - r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0"); - assertTrue(r.isHostRoute()); - assertFalse(r.isDefaultRoute()); - assertFalse(r.isIPv4Default()); - assertFalse(r.isIPv6Default()); + r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0"); + assertTrue(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); - r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0"); - assertTrue(r.isHostRoute()); - assertFalse(r.isDefaultRoute()); - assertFalse(r.isIPv4Default()); - assertFalse(r.isIPv6Default()); + r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0"); + assertTrue(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); - r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0"); - assertTrue(r.isHostRoute()); - assertFalse(r.isDefaultRoute()); - assertFalse(r.isIPv4Default()); - assertFalse(r.isIPv6Default()); + r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0"); + assertTrue(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); - r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0"); - assertTrue(r.isHostRoute()); - assertFalse(r.isDefaultRoute()); - assertFalse(r.isIPv4Default()); - assertFalse(r.isIPv6Default()); + r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0"); + assertTrue(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); + + r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0"); + assertTrue(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); + + r = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE); + assertFalse(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); + + r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE); + assertFalse(r.isHostRoute()); + assertFalse(r.isDefaultRoute()); + assertFalse(r.isIPv4Default()); + assertFalse(r.isIPv6Default()); } public void testTruncation() { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 44380cce1c..0eba746d7f 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.content.pm.PackageManager.GET_PERMISSIONS; +import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; @@ -60,11 +62,13 @@ import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +import static android.net.RouteInfo.RTN_UNREACHABLE; import static com.android.internal.util.TestUtils.waitForIdleHandler; import static com.android.internal.util.TestUtils.waitForIdleLooper; import static com.android.internal.util.TestUtils.waitForIdleSerialExecutor; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -72,12 +76,14 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -97,6 +103,10 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; @@ -151,6 +161,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.system.Os; import android.test.mock.MockContentResolver; @@ -186,6 +197,7 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; @@ -194,6 +206,7 @@ import org.mockito.stubbing.Answer; import java.io.IOException; import java.net.DatagramSocket; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; @@ -261,6 +274,8 @@ public class ConnectivityServiceTest { @Mock IDnsResolver mMockDnsResolver; @Mock INetd mMockNetd; @Mock NetworkStackClient mNetworkStack; + @Mock PackageManager mPackageManager; + @Mock UserManager mUserManager; private ArgumentCaptor mStringArrayCaptor = ArgumentCaptor.forClass(String[].class); @@ -331,6 +346,7 @@ public class ConnectivityServiceTest { if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm; if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class); if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack; + if (Context.USER_SERVICE.equals(name)) return mUserManager; return super.getSystemService(name); } @@ -343,6 +359,11 @@ public class ConnectivityServiceTest { public Resources getResources() { return mResources; } + + @Override + public PackageManager getPackageManager() { + return mPackageManager; + } } public void waitForIdle(int timeoutMsAsInt) { @@ -1057,7 +1078,7 @@ public class ConnectivityServiceTest { public WrappedConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager, IpConnectivityLog log, INetd netd, IDnsResolver dnsResolver) { - super(context, netManager, statsService, policyManager, dnsResolver, log); + super(context, netManager, statsService, policyManager, dnsResolver, log, netd); mNetd = netd; mLingerDelayMs = TEST_LINGER_DELAY_MS; } @@ -1196,6 +1217,11 @@ public class ConnectivityServiceTest { fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms"); } + private static final int VPN_USER = 0; + private static final int APP1_UID = UserHandle.getUid(VPN_USER, 10100); + private static final int APP2_UID = UserHandle.getUid(VPN_USER, 10101); + private static final int VPN_UID = UserHandle.getUid(VPN_USER, 10043); + @Before public void setUp() throws Exception { mContext = InstrumentationRegistry.getContext(); @@ -1203,6 +1229,17 @@ public class ConnectivityServiceTest { MockitoAnnotations.initMocks(this); when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics); + when(mUserManager.getUsers(eq(true))).thenReturn( + Arrays.asList(new UserInfo[] { + new UserInfo(VPN_USER, "", 0), + })); + when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn( + Arrays.asList(new PackageInfo[] { + buildPackageInfo(/* SYSTEM */ false, APP1_UID), + buildPackageInfo(/* SYSTEM */ false, APP2_UID), + buildPackageInfo(/* SYSTEM */ false, VPN_UID) + })); + // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. // http://b/25897652 . if (Looper.myLooper() == null) { @@ -6129,4 +6166,165 @@ public class ConnectivityServiceTest { assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork())); assertEquals(testProxyInfo, mService.getProxyForNetwork(null)); } + + @Test + public void testFullyRoutedVpnResultsInInterfaceFilteringRules() throws Exception { + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName("tun0"); + 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 vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final MockNetworkAgent vpnNetworkAgent = establishVpn(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 + ArgumentCaptor 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(); + waitForIdle(); + + // Disconnected VPN should have interface rules removed + verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture()); + assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID); + assertNull(mService.mPermissionMonitor.getVpnUidRanges("tun0")); + } + + @Test + public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception { + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName("tun0"); + 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 vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange); + + // Legacy VPN should not have interface rules set up + verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any()); + } + + public void testLocalIpv4OnlyVpnDoesNotResultInInterfaceFilteringRule() + throws Exception { + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName("tun0"); + lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0")); + 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 vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange); + + // IPv6 unreachable route should not be misinterpreted as a default route + verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any()); + } + + @Test + public void testVpnHandoverChangesInterfaceFilteringRule() throws Exception { + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName("tun0"); + 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 vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final MockNetworkAgent vpnNetworkAgent = establishVpn(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 + ArgumentCaptor 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); + + reset(mMockNetd); + InOrder inOrder = inOrder(mMockNetd); + lp.setInterfaceName("tun1"); + vpnNetworkAgent.sendLinkProperties(lp); + waitForIdle(); + // VPN handover (switch to a new interface) should result in rules being updated (old rules + // removed first, then new rules added) + inOrder.verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture()); + assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID); + inOrder.verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture()); + assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID); + + reset(mMockNetd); + lp = new LinkProperties(); + lp.setInterfaceName("tun1"); + lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun1")); + vpnNetworkAgent.sendLinkProperties(lp); + waitForIdle(); + // VPN not routing everything should no longer have interface filtering rules + verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture()); + assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID); + + reset(mMockNetd); + lp = new LinkProperties(); + lp.setInterfaceName("tun1"); + lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); + vpnNetworkAgent.sendLinkProperties(lp); + waitForIdle(); + // Back to routing all IPv6 traffic should have filtering rules + verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture()); + assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID); + } + + @Test + public void testUidUpdateChangesInterfaceFilteringRule() throws Exception { + LinkProperties lp = new LinkProperties(); + lp.setInterfaceName("tun0"); + 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 MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, + Collections.singleton(vpnRange)); + + reset(mMockNetd); + InOrder inOrder = inOrder(mMockNetd); + + // Update to new range which is old range minus APP1, i.e. only APP2 + final Set newRanges = new HashSet<>(Arrays.asList( + new UidRange(vpnRange.start, APP1_UID - 1), + new UidRange(APP1_UID + 1, vpnRange.stop))); + vpnNetworkAgent.setUids(newRanges); + waitForIdle(); + + ArgumentCaptor uidCaptor = ArgumentCaptor.forClass(int[].class); + // Verify old rules are removed before new rules are added + inOrder.verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture()); + assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID); + inOrder.verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture()); + assertContainsExactly(uidCaptor.getValue(), APP2_UID); + } + + + private MockNetworkAgent establishVpn(LinkProperties lp, int establishingUid, + Set vpnRange) { + final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN, lp); + vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.connect(); + mMockVpn.setUids(vpnRange); + vpnNetworkAgent.connect(true); + waitForIdle(); + return vpnNetworkAgent; + } + + private void assertContainsExactly(int[] actual, int... expected) { + int[] sortedActual = Arrays.copyOf(actual, actual.length); + int[] sortedExpected = Arrays.copyOf(expected, expected.length); + Arrays.sort(sortedActual); + Arrays.sort(sortedExpected); + assertArrayEquals(sortedExpected, sortedActual); + } + + private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid) { + final PackageInfo packageInfo = new PackageInfo(); + packageInfo.requestedPermissions = new String[0]; + packageInfo.applicationInfo = new ApplicationInfo(); + packageInfo.applicationInfo.privateFlags = 0; + packageInfo.applicationInfo.uid = UserHandle.getUid(UserHandle.USER_SYSTEM, + UserHandle.getAppId(uid)); + return packageInfo; + } } diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index 106cd1fba8..62a4718965 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -28,6 +28,7 @@ import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR; 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; import static android.os.Process.SYSTEM_UID; import static com.android.server.connectivity.PermissionMonitor.NETWORK; @@ -36,13 +37,16 @@ import static com.android.server.connectivity.PermissionMonitor.SYSTEM; import static junit.framework.Assert.fail; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.AdditionalMatchers.aryEq; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.anyInt; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -53,10 +57,12 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageList; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.UserInfo; import android.net.INetd; +import android.net.UidRange; import android.os.Build; -import android.os.INetworkManagementService; import android.os.UserHandle; +import android.os.UserManager; import android.util.SparseIntArray; import androidx.test.filters.SmallTest; @@ -73,7 +79,12 @@ import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + @RunWith(AndroidJUnit4.class) @SmallTest @@ -84,10 +95,12 @@ public class PermissionMonitorTest { private static final int MOCK_UID2 = 10086; private static final int SYSTEM_UID1 = 1000; private static final int SYSTEM_UID2 = 1008; + private static final int VPN_UID = 10002; private static final String MOCK_PACKAGE1 = "appName1"; private static final String MOCK_PACKAGE2 = "appName2"; private static final String SYSTEM_PACKAGE1 = "sysName1"; private static final String SYSTEM_PACKAGE2 = "sysName2"; + private static final String VPN_PACKAGE = "vpnApp"; private static final String PARTITION_SYSTEM = "system"; private static final String PARTITION_OEM = "oem"; private static final String PARTITION_PRODUCT = "product"; @@ -97,9 +110,9 @@ public class PermissionMonitorTest { @Mock private Context mContext; @Mock private PackageManager mPackageManager; - @Mock private INetworkManagementService mNMS; @Mock private INetd mNetdService; @Mock private PackageManagerInternal mMockPmi; + @Mock private UserManager mUserManager; private PackageManagerInternal.PackageListObserver mObserver; private PermissionMonitor mPermissionMonitor; @@ -108,7 +121,14 @@ public class PermissionMonitorTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mContext.getPackageManager()).thenReturn(mPackageManager); - mPermissionMonitor = spy(new PermissionMonitor(mContext, mNMS, mNetdService)); + when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager); + when(mUserManager.getUsers(eq(true))).thenReturn( + Arrays.asList(new UserInfo[] { + new UserInfo(MOCK_USER1, "", 0), + new UserInfo(MOCK_USER2, "", 0), + })); + + mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService)); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mMockPmi); @@ -134,7 +154,7 @@ public class PermissionMonitorTest { return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid); } - private PackageInfo packageInfoWithPermissions(String[] permissions, String partition) { + private static PackageInfo packageInfoWithPermissions(String[] permissions, String partition) { int[] requestedPermissionsFlags = new int[permissions.length]; for (int i = 0; i < permissions.length; i++) { requestedPermissionsFlags[i] = REQUESTED_PERMISSION_GRANTED; @@ -143,7 +163,7 @@ public class PermissionMonitorTest { requestedPermissionsFlags); } - private PackageInfo packageInfoWithPermissions(String[] permissions, String partition, + private static PackageInfo packageInfoWithPermissions(String[] permissions, String partition, int[] requestedPermissionsFlags) { final PackageInfo packageInfo = new PackageInfo(); packageInfo.requestedPermissions = permissions; @@ -165,6 +185,18 @@ public class PermissionMonitorTest { return packageInfo; } + private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) { + final PackageInfo pkgInfo; + if (hasSystemPermission) { + pkgInfo = packageInfoWithPermissions(new String[] {CHANGE_NETWORK_STATE, NETWORK_STACK}, + PARTITION_SYSTEM); + } else { + pkgInfo = packageInfoWithPermissions(new String[] {}, ""); + } + pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid)); + return pkgInfo; + } + @Test public void testHasPermission() { PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM); @@ -245,14 +277,14 @@ public class PermissionMonitorTest { assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE)); } - private class NMSMonitor { + private class NetdMonitor { private final HashMap mApps = new HashMap<>(); - NMSMonitor(INetworkManagementService mockNMS) throws Exception { + NetdMonitor(INetd mockNetd) throws Exception { // Add hook to verify and track result of setPermission. doAnswer((InvocationOnMock invocation) -> { final Object[] args = invocation.getArguments(); - final Boolean isSystem = args[0].equals("SYSTEM"); + final Boolean isSystem = args[0].equals(INetd.PERMISSION_SYSTEM); for (final int uid : (int[]) args[1]) { // TODO: Currently, permission monitor will send duplicate commands for each uid // corresponding to each user. Need to fix that and uncomment below test. @@ -262,7 +294,7 @@ public class PermissionMonitorTest { mApps.put(uid, isSystem); } return null; - }).when(mockNMS).setPermission(anyString(), any(int[].class)); + }).when(mockNetd).networkSetPermissionForUser(anyInt(), any(int[].class)); // Add hook to verify and track result of clearPermission. doAnswer((InvocationOnMock invocation) -> { @@ -276,7 +308,7 @@ public class PermissionMonitorTest { mApps.remove(uid); } return null; - }).when(mockNMS).clearPermission(any(int[].class)); + }).when(mockNetd).networkClearPermissionForUser(any(int[].class)); } public void expectPermission(Boolean permission, int[] users, int[] apps) { @@ -307,7 +339,7 @@ public class PermissionMonitorTest { @Test public void testUserAndPackageAddRemove() throws Exception { - final NMSMonitor mNMSMonitor = new NMSMonitor(mNMS); + final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService); // MOCK_UID1: MOCK_PACKAGE1 only has network permission. // SYSTEM_UID: SYSTEM_PACKAGE1 has system permission. @@ -323,48 +355,123 @@ public class PermissionMonitorTest { // Add SYSTEM_PACKAGE2, expect only have network permission. mPermissionMonitor.onUserAdded(MOCK_USER1); addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID); - mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID}); + mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID}); // Add SYSTEM_PACKAGE1, expect permission escalate. addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID); - mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID}); + mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID}); mPermissionMonitor.onUserAdded(MOCK_USER2); - mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2}, + mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2}, new int[]{SYSTEM_UID}); addPackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1); - mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2}, + mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2}, new int[]{SYSTEM_UID}); - mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2}, + mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1}); // Remove MOCK_UID1, expect no permission left for all user. mPermissionMonitor.onPackageRemoved(MOCK_UID1); removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1); - mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1}); + mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1}); // Remove SYSTEM_PACKAGE1, expect permission downgrade. when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2}); removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID); - mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2}, + mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2}, new int[]{SYSTEM_UID}); mPermissionMonitor.onUserRemoved(MOCK_USER1); - mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID}); + mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID}); // Remove all packages, expect no permission left. when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{}); removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID); - mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, + mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{SYSTEM_UID, MOCK_UID1}); // Remove last user, expect no redundant clearPermission is invoked. mPermissionMonitor.onUserRemoved(MOCK_USER2); - mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, + mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{SYSTEM_UID, MOCK_UID1}); } + @Test + public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception { + when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn( + Arrays.asList(new PackageInfo[] { + buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1), + buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1), + buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1), + buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1) + })); + when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn( + buildPackageInfo(false, MOCK_UID1, MOCK_USER1)); + mPermissionMonitor.startMonitoring(); + // Every app on user 0 except MOCK_UID2 are under VPN. + final Set vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] { + new UidRange(0, MOCK_UID2 - 1), + new UidRange(MOCK_UID2 + 1, UserHandle.PER_USER_RANGE - 1)})); + final Set vpnRange2 = Collections.singleton(new UidRange(MOCK_UID2, MOCK_UID2)); + + // When VPN is connected, expect a rule to be set up for user app MOCK_UID1 + mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange1, VPN_UID); + verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), + aryEq(new int[] {MOCK_UID1})); + + reset(mNetdService); + + // When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated + mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1)); + verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1})); + mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1)); + verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), + aryEq(new int[] {MOCK_UID1})); + + reset(mNetdService); + + // During VPN uid update (vpnRange1 -> vpnRange2), ConnectivityService first deletes the + // old UID rules then adds the new ones. Expect netd to be updated + mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange1, VPN_UID); + verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1})); + mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange2, VPN_UID); + verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), + aryEq(new int[] {MOCK_UID2})); + + reset(mNetdService); + + // When VPN is disconnected, expect rules to be torn down + mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange2, VPN_UID); + verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID2})); + assertNull(mPermissionMonitor.getVpnUidRanges("tun0")); + } + + @Test + public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception { + when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn( + Arrays.asList(new PackageInfo[] { + buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1), + buildPackageInfo(false, VPN_UID, MOCK_USER1) + })); + when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn( + buildPackageInfo(false, MOCK_UID1, MOCK_USER1)); + + mPermissionMonitor.startMonitoring(); + final Set vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1)); + mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange, VPN_UID); + + // Newly-installed package should have uid rules added + mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1)); + verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), + aryEq(new int[] {MOCK_UID1})); + + // Removed package should have its uid rules removed + mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1)); + verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1})); + } + + // Normal package add/remove operations will trigger multiple intent for uids corresponding to // each user. To simulate generic package operations, the onPackageAdded/Removed will need to be // called multiple times with the uid corresponding to each user. From a484cc95d64b856ed4068f1b91cd27155299c0fa Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 12 Apr 2019 19:50:22 +0900 Subject: [PATCH 058/130] Revert new tests and PackageManager mock A mocked PackageManager caused test failures in existing tests. Revert that for now to make tests pass again. Bug: 114231106 Bug: 130397860 Test: atest FrameworksNetTests Merged-In: Ib59e211d4329f885108de9ea0a74669ffb144e17 (cherry picked from commit 8574c9bf350ca60e2b21c759aa75bc3843ffde17) Change-Id: I603a0b0dfb67a942679a668c182aa650774c80b2 --- .../server/ConnectivityServiceTest.java | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 0eba746d7f..0abd6c613d 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -16,8 +16,6 @@ package com.android.server; -import static android.content.pm.PackageManager.GET_PERMISSIONS; -import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; @@ -105,7 +103,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.ConnectivityManager; @@ -274,7 +271,6 @@ public class ConnectivityServiceTest { @Mock IDnsResolver mMockDnsResolver; @Mock INetd mMockNetd; @Mock NetworkStackClient mNetworkStack; - @Mock PackageManager mPackageManager; @Mock UserManager mUserManager; private ArgumentCaptor mStringArrayCaptor = ArgumentCaptor.forClass(String[].class); @@ -359,11 +355,6 @@ public class ConnectivityServiceTest { public Resources getResources() { return mResources; } - - @Override - public PackageManager getPackageManager() { - return mPackageManager; - } } public void waitForIdle(int timeoutMsAsInt) { @@ -1233,12 +1224,6 @@ public class ConnectivityServiceTest { Arrays.asList(new UserInfo[] { new UserInfo(VPN_USER, "", 0), })); - when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn( - Arrays.asList(new PackageInfo[] { - buildPackageInfo(/* SYSTEM */ false, APP1_UID), - buildPackageInfo(/* SYSTEM */ false, APP2_UID), - buildPackageInfo(/* SYSTEM */ false, VPN_UID) - })); // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. // http://b/25897652 . @@ -6168,6 +6153,7 @@ public class ConnectivityServiceTest { } @Test + @Ignore public void testFullyRoutedVpnResultsInInterfaceFilteringRules() throws Exception { LinkProperties lp = new LinkProperties(); lp.setInterfaceName("tun0"); @@ -6194,6 +6180,7 @@ public class ConnectivityServiceTest { } @Test + @Ignore public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception { LinkProperties lp = new LinkProperties(); lp.setInterfaceName("tun0"); @@ -6206,6 +6193,8 @@ public class ConnectivityServiceTest { verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any()); } + @Test + @Ignore public void testLocalIpv4OnlyVpnDoesNotResultInInterfaceFilteringRule() throws Exception { LinkProperties lp = new LinkProperties(); @@ -6221,6 +6210,7 @@ public class ConnectivityServiceTest { } @Test + @Ignore public void testVpnHandoverChangesInterfaceFilteringRule() throws Exception { LinkProperties lp = new LinkProperties(); lp.setInterfaceName("tun0"); @@ -6270,6 +6260,7 @@ public class ConnectivityServiceTest { } @Test + @Ignore public void testUidUpdateChangesInterfaceFilteringRule() throws Exception { LinkProperties lp = new LinkProperties(); lp.setInterfaceName("tun0"); From 0ac2d0bd620a8bc17b7738f125d6889795d44a8f Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Wed, 24 Apr 2019 03:05:12 -0700 Subject: [PATCH 059/130] Reinstate new VPN uid filtering unit tests Mock out PackageManager and returns correct information corresponding to the test app package itself. Test: atest --generate-new-metrics 10 com.android.server.ConnectivityServiceTest Bug: 114231106 Bug: 130397860 Merged-In: Ic2faef44831575b2d03bc00ef2553d5c549adc95 Change-Id: Ic2faef44831575b2d03bc00ef2553d5c549adc95 (cherry picked from commit 4469b1d8a543613d91a58a88488fd2022a0696b9) --- .../server/ConnectivityServiceTest.java | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 0abd6c613d..24952f9389 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.content.pm.PackageManager.GET_PERMISSIONS; +import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; @@ -103,6 +105,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.ConnectivityManager; @@ -145,6 +148,7 @@ import android.net.metrics.IpConnectivityLog; import android.net.shared.NetworkMonitorUtils; import android.net.shared.PrivateDnsConfig; import android.net.util.MultinetworkPolicyTracker; +import android.os.Binder; import android.os.ConditionVariable; import android.os.Handler; import android.os.HandlerThread; @@ -271,6 +275,7 @@ public class ConnectivityServiceTest { @Mock IDnsResolver mMockDnsResolver; @Mock INetd mMockNetd; @Mock NetworkStackClient mNetworkStack; + @Mock PackageManager mPackageManager; @Mock UserManager mUserManager; private ArgumentCaptor mStringArrayCaptor = ArgumentCaptor.forClass(String[].class); @@ -355,7 +360,12 @@ public class ConnectivityServiceTest { public Resources getResources() { return mResources; } - } + + @Override + public PackageManager getPackageManager() { + return mPackageManager; + } + } public void waitForIdle(int timeoutMsAsInt) { long timeoutMs = timeoutMsAsInt; @@ -1230,6 +1240,7 @@ public class ConnectivityServiceTest { if (Looper.myLooper() == null) { Looper.prepare(); } + mockDefaultPackages(); FakeSettingsProvider.clearSettingsProvider(); mServiceContext = new MockContext(InstrumentationRegistry.getContext(), @@ -1282,7 +1293,24 @@ public class ConnectivityServiceTest { FakeSettingsProvider.clearSettingsProvider(); } - private static int transportToLegacyType(int transport) { + private void mockDefaultPackages() throws Exception { + final String testPackageName = mContext.getPackageName(); + final PackageInfo testPackageInfo = mContext.getPackageManager().getPackageInfo( + testPackageName, PackageManager.GET_PERMISSIONS); + when(mPackageManager.getPackagesForUid(Binder.getCallingUid())).thenReturn( + new String[] {testPackageName}); + when(mPackageManager.getPackageInfoAsUser(eq(testPackageName), anyInt(), + eq(UserHandle.getCallingUserId()))).thenReturn(testPackageInfo); + + when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn( + Arrays.asList(new PackageInfo[] { + buildPackageInfo(/* SYSTEM */ false, APP1_UID), + buildPackageInfo(/* SYSTEM */ false, APP2_UID), + buildPackageInfo(/* SYSTEM */ false, VPN_UID) + })); + } + + private static int transportToLegacyType(int transport) { switch (transport) { case TRANSPORT_ETHERNET: return TYPE_ETHERNET; @@ -6153,7 +6181,6 @@ public class ConnectivityServiceTest { } @Test - @Ignore public void testFullyRoutedVpnResultsInInterfaceFilteringRules() throws Exception { LinkProperties lp = new LinkProperties(); lp.setInterfaceName("tun0"); @@ -6180,7 +6207,6 @@ public class ConnectivityServiceTest { } @Test - @Ignore public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception { LinkProperties lp = new LinkProperties(); lp.setInterfaceName("tun0"); @@ -6194,7 +6220,6 @@ public class ConnectivityServiceTest { } @Test - @Ignore public void testLocalIpv4OnlyVpnDoesNotResultInInterfaceFilteringRule() throws Exception { LinkProperties lp = new LinkProperties(); @@ -6210,7 +6235,6 @@ public class ConnectivityServiceTest { } @Test - @Ignore public void testVpnHandoverChangesInterfaceFilteringRule() throws Exception { LinkProperties lp = new LinkProperties(); lp.setInterfaceName("tun0"); @@ -6260,7 +6284,6 @@ public class ConnectivityServiceTest { } @Test - @Ignore public void testUidUpdateChangesInterfaceFilteringRule() throws Exception { LinkProperties lp = new LinkProperties(); lp.setInterfaceName("tun0"); From 72d5c3fc4e1c4ec0adf71a6b44bf94e964c93071 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 24 Apr 2019 22:35:58 -0700 Subject: [PATCH 060/130] Update exception type thrown when NetworkStack is missing rethrowFromSystemServer is throwing DeadSystemException which is different from the original log message. Thus, update the way to rethrow the same RemoteException. Bug: 130028724 Test: atest FrameworksNetTest Test: Kill NetworkStack and check the log message Change-Id: I60862e276dd4e2d143278b272a9ba54219acce26 Merged-In: Ic1766e839f8f06b539d5f6cfecd29547021fd1d9 Merged-In: I67005a5384888e8acaf1249af79484e2d5ed6f1f (cherry picked from commit 7f581219e1a4706ea2b4438322a299986847b1c2) --- .../com/android/server/ConnectivityService.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 313c0a867d..f5710e3271 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2862,7 +2862,7 @@ public class ConnectivityService extends IConnectivityManager.Stub try { nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel()); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + e.rethrowAsRuntimeException(); } // With Private DNS bypass support, we can proceed to update the @@ -3032,7 +3032,7 @@ public class ConnectivityService extends IConnectivityManager.Stub try { nai.networkMonitor().notifyNetworkDisconnected(); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + e.rethrowAsRuntimeException(); } mNetworkAgentInfos.remove(nai.messenger); nai.clatd.update(); @@ -3421,7 +3421,7 @@ public class ConnectivityService extends IConnectivityManager.Stub try { nai.networkMonitor().setAcceptPartialConnectivity(); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + e.rethrowAsRuntimeException(); } } } @@ -3457,7 +3457,7 @@ public class ConnectivityService extends IConnectivityManager.Stub try { nai.networkMonitor().launchCaptivePortalApp(); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + e.rethrowAsRuntimeException(); } }); } @@ -4085,7 +4085,7 @@ public class ConnectivityService extends IConnectivityManager.Stub try { nai.networkMonitor().forceReevaluation(uid); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + e.rethrowAsRuntimeException(); } } @@ -5458,7 +5458,7 @@ public class ConnectivityService extends IConnectivityManager.Stub try { networkMonitor.start(); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + e.rethrowAsRuntimeException(); } nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger); NetworkInfo networkInfo = nai.networkInfo; @@ -5515,7 +5515,7 @@ public class ConnectivityService extends IConnectivityManager.Stub try { networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + e.rethrowAsRuntimeException(); } if (networkAgent.everConnected) { notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED); @@ -6521,7 +6521,7 @@ public class ConnectivityService extends IConnectivityManager.Stub networkAgent.networkMonitor().notifyNetworkConnected( networkAgent.linkProperties, networkAgent.networkCapabilities); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + e.rethrowAsRuntimeException(); } scheduleUnvalidatedPrompt(networkAgent); From 9ede7e939943598e4c8520b68cce9ee83992cfb0 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Mon, 22 Apr 2019 07:41:42 -0700 Subject: [PATCH 061/130] Move more network unit tests to common tests This adds the moved tests to CTS as well. The moved unit tests are appropriate for CTS as they test data holder classes that need to function properly for apps to work. Test: atest FrameworksNetTests Test: atest CtsNetTestCases: added tests pass Bug: 129199900 Change-Id: I895d2b57da658d5bed28ebe128611d5d15835742 Merged-In: I9f708a252ab606b782f5f828dce8c1690c3703bf Merged-In: I895d2b57da658d5bed28ebe128611d5d15835742 (cherry picked from commit cc21fbd483138771dae04f4d86ab411e2e88e575) --- tests/net/Android.bp | 1 + tests/net/common/Android.bp | 1 + tests/net/{ => common}/java/android/net/LinkAddressTest.java | 0 .../net/{ => common}/java/android/net/LinkPropertiesTest.java | 0 .../{ => common}/java/android/net/NetworkCapabilitiesTest.java | 0 tests/net/{ => common}/java/android/net/NetworkTest.java | 0 tests/net/{ => common}/java/android/net/RouteInfoTest.java | 0 .../java/android/net/StaticIpConfigurationTest.java | 0 .../{ => common}/java/android/net/apf/ApfCapabilitiesTest.java | 3 +-- 9 files changed, 3 insertions(+), 2 deletions(-) rename tests/net/{ => common}/java/android/net/LinkAddressTest.java (100%) rename tests/net/{ => common}/java/android/net/LinkPropertiesTest.java (100%) rename tests/net/{ => common}/java/android/net/NetworkCapabilitiesTest.java (100%) rename tests/net/{ => common}/java/android/net/NetworkTest.java (100%) rename tests/net/{ => common}/java/android/net/RouteInfoTest.java (100%) rename tests/net/{ => common}/java/android/net/StaticIpConfigurationTest.java (100%) rename tests/net/{ => common}/java/android/net/apf/ApfCapabilitiesTest.java (96%) diff --git a/tests/net/Android.bp b/tests/net/Android.bp index 689abed19a..1fbb6580c3 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -6,6 +6,7 @@ java_defaults { static_libs: [ "FrameworksNetCommonTests", "frameworks-base-testutils", + "frameworks-net-testutils", "framework-protos", "androidx.test.rules", "mockito-target-minus-junit4", diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp index 0a1ac75aac..9ee5858377 100644 --- a/tests/net/common/Android.bp +++ b/tests/net/common/Android.bp @@ -21,6 +21,7 @@ java_library { srcs: ["java/**/*.java"], static_libs: [ "androidx.test.rules", + "frameworks-net-testutils", "junit", ], libs: [ diff --git a/tests/net/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java similarity index 100% rename from tests/net/java/android/net/LinkAddressTest.java rename to tests/net/common/java/android/net/LinkAddressTest.java diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java similarity index 100% rename from tests/net/java/android/net/LinkPropertiesTest.java rename to tests/net/common/java/android/net/LinkPropertiesTest.java diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java similarity index 100% rename from tests/net/java/android/net/NetworkCapabilitiesTest.java rename to tests/net/common/java/android/net/NetworkCapabilitiesTest.java diff --git a/tests/net/java/android/net/NetworkTest.java b/tests/net/common/java/android/net/NetworkTest.java similarity index 100% rename from tests/net/java/android/net/NetworkTest.java rename to tests/net/common/java/android/net/NetworkTest.java diff --git a/tests/net/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java similarity index 100% rename from tests/net/java/android/net/RouteInfoTest.java rename to tests/net/common/java/android/net/RouteInfoTest.java diff --git a/tests/net/java/android/net/StaticIpConfigurationTest.java b/tests/net/common/java/android/net/StaticIpConfigurationTest.java similarity index 100% rename from tests/net/java/android/net/StaticIpConfigurationTest.java rename to tests/net/common/java/android/net/StaticIpConfigurationTest.java diff --git a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java similarity index 96% rename from tests/net/java/android/net/apf/ApfCapabilitiesTest.java rename to tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java index 75752c33da..7238895b36 100644 --- a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java +++ b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java @@ -19,11 +19,10 @@ package android.net.apf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; -import android.net.shared.ParcelableTestUtil; - import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.ParcelableTestUtil; import com.android.internal.util.TestUtils; import org.junit.Test; From d44040df36c8ee64ae80005f3ed2dc708ffc1644 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 25 Apr 2019 18:06:28 -0700 Subject: [PATCH 062/130] Make DNS cache lifecycle management explicit 1. ConnectivityService calls netd binder to create/destroy network directly. 2. Call dnsresolver binder to create/destroy cache after create/destroy network. 3. Remove unused network create/destroy methods in NetworkManagementService. Bug: 129453995 Test: atest FrameworksNetTests Merged-In: I388e208143c38b89bcbb0589de393250024d59aa (cherry picked from commit 204ca13e63f063f044ac4ad3b96f08b473fe59df) Change-Id: I4d3dfd9305b60a724aa2dc38448948d8e710c932 --- .../android/server/ConnectivityService.java | 51 +++++++++++-------- .../server/connectivity/DnsManager.java | 6 --- .../server/ConnectivityServiceTest.java | 14 ++++- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f5710e3271..55f9826eff 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3071,11 +3071,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // fallback network the default or requested a new network from the // NetworkFactories, so network traffic isn't interrupted for an unnecessarily // long time. - try { - mNetd.networkDestroy(nai.network.netId); - } catch (RemoteException | ServiceSpecificException e) { - loge("Exception destroying network: " + e); - } + destroyNativeNetwork(nai); mDnsManager.removeNetwork(nai.network); } synchronized (mNetworkForNetId) { @@ -3083,6 +3079,35 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) { + try { + // This should never fail. Specifying an already in use NetID will cause failure. + if (networkAgent.isVPN()) { + mNetd.networkCreateVpn(networkAgent.network.netId, + (networkAgent.networkMisc == null + || !networkAgent.networkMisc.allowBypass)); + } else { + mNetd.networkCreatePhysical(networkAgent.network.netId, + getNetworkPermission(networkAgent.networkCapabilities)); + } + mDnsResolver.createNetworkCache(networkAgent.network.netId); + return true; + } catch (RemoteException | ServiceSpecificException e) { + loge("Error creating network " + networkAgent.network.netId + ": " + + e.getMessage()); + return false; + } + } + + private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) { + try { + mNetd.networkDestroy(networkAgent.network.netId); + mDnsResolver.destroyNetworkCache(networkAgent.network.netId); + } catch (RemoteException | ServiceSpecificException e) { + loge("Exception destroying network: " + e); + } + } + // If this method proves to be too slow then we can maintain a separate // pendingIntent => NetworkRequestInfo map. // This method assumes that every non-null PendingIntent maps to exactly 1 NetworkRequestInfo. @@ -6476,21 +6501,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // A network that has just connected has zero requests and is thus a foreground network. networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND); - try { - // This should never fail. Specifying an already in use NetID will cause failure. - if (networkAgent.isVPN()) { - mNMS.createVirtualNetwork(networkAgent.network.netId, - (networkAgent.networkMisc == null || - !networkAgent.networkMisc.allowBypass)); - } else { - mNMS.createPhysicalNetwork(networkAgent.network.netId, - getNetworkPermission(networkAgent.networkCapabilities)); - } - } catch (Exception e) { - loge("Error creating network " + networkAgent.network.netId + ": " - + e.getMessage()); - return; - } + if (!createNativeNetwork(networkAgent)) return; networkAgent.created = true; } diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index e33392d359..2321afb7df 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -263,12 +263,6 @@ public class DnsManager { } public void removeNetwork(Network network) { - try { - mDnsResolver.clearResolverConfiguration(network.netId); - } catch (RemoteException | ServiceSpecificException e) { - Slog.e(TAG, "Error clearing DNS configuration: " + e); - return; - } mPrivateDnsMap.remove(network.netId); mPrivateDnsValidationMap.remove(network.netId); } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 16ec134794..c15775fc47 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -4894,7 +4894,10 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(cellLp); mCellNetworkAgent.connect(false); waitForIdle(); - // CS tells netd about the empty DNS config for this network. + + verify(mMockDnsResolver, times(1)).createNetworkCache( + eq(mCellNetworkAgent.getNetwork().netId)); + // CS tells dnsresolver about the empty DNS config for this network. verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any()); reset(mMockDnsResolver); @@ -4978,6 +4981,8 @@ public class ConnectivityServiceTest { mCellNetworkAgent.sendLinkProperties(cellLp); mCellNetworkAgent.connect(false); waitForIdle(); + verify(mMockDnsResolver, times(1)).createNetworkCache( + eq(mCellNetworkAgent.getNetwork().netId)); verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration( mResolverParamsParcelCaptor.capture()); ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue(); @@ -5851,12 +5856,17 @@ public class ConnectivityServiceTest { cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME)); reset(mNetworkManagementService); reset(mMockDnsResolver); + reset(mMockNetd); when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME)) .thenReturn(getClatInterfaceConfig(myIpv4)); // Connect with ipv6 link properties. Expect prefix discovery to be started. mCellNetworkAgent.sendLinkProperties(cellLp); mCellNetworkAgent.connect(true); + + verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt()); + verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId)); + networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId); @@ -6048,7 +6058,7 @@ public class ConnectivityServiceTest { verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME)); verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId)); verify(mMockDnsResolver, times(1)) - .clearResolverConfiguration(eq(mCellNetworkAgent.getNetwork().netId)); + .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId)); // Disconnect wifi ConditionVariable cv = waitForConnectivityBroadcasts(1); From 5e05934c54caaa147a0bdcbe5e675694a6603ce6 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Tue, 23 Apr 2019 11:00:58 -0700 Subject: [PATCH 063/130] Add tests for DhcpErrorEvent The tests are run both in unit and CTS tests. Test: atest FrameworksNetTests NetworkStackTestCases Bug: 129200175 Change-Id: I78d78dd421cc3ffea774ff5eaa6aa758debc9cf2 Merged-In: I9b65a2eef94567d2b79a9955619938e64906080d Merged-In: I78d78dd421cc3ffea774ff5eaa6aa758debc9cf2 (cherry picked from commit 9e046d509a37c6f37b4757f1681846cee60cfd5c) --- tests/net/common/Android.bp | 2 +- .../java/android/net/LinkPropertiesTest.java | 4 +- .../android/net/apf/ApfCapabilitiesTest.java | 2 +- .../android/net/metrics/DhcpErrorEventTest.kt | 67 +++++++++++++++++++ .../net/TcpKeepalivePacketDataTest.java | 2 +- 5 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp index 9ee5858377..3b2e34a159 100644 --- a/tests/net/common/Android.bp +++ b/tests/net/common/Android.bp @@ -18,7 +18,7 @@ // They must be fast and stable, and exercise public or test APIs. java_library { name: "FrameworksNetCommonTests", - srcs: ["java/**/*.java"], + srcs: ["java/**/*.java", "java/**/*.kt"], static_libs: [ "androidx.test.rules", "frameworks-net-testutils", diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java index 417729150b..709f5f69aa 100644 --- a/tests/net/common/java/android/net/LinkPropertiesTest.java +++ b/tests/net/common/java/android/net/LinkPropertiesTest.java @@ -868,12 +868,12 @@ public class LinkPropertiesTest { source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96")); - TestUtils.assertParcelingIsLossless(source, LinkProperties.CREATOR); + TestUtils.assertParcelingIsLossless(source); } @Test public void testParcelUninitialized() throws Exception { LinkProperties empty = new LinkProperties(); - TestUtils.assertParcelingIsLossless(empty, LinkProperties.CREATOR); + TestUtils.assertParcelingIsLossless(empty); } } diff --git a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java index 7238895b36..3ed8a86b2f 100644 --- a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java +++ b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java @@ -36,7 +36,7 @@ public class ApfCapabilitiesTest { final ApfCapabilities caps = new ApfCapabilities(123, 456, 789); ParcelableTestUtil.assertFieldCountEquals(3, ApfCapabilities.class); - TestUtils.assertParcelingIsLossless(caps, ApfCapabilities.CREATOR); + TestUtils.assertParcelingIsLossless(caps); } @Test diff --git a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt new file mode 100644 index 0000000000..e19195322e --- /dev/null +++ b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt @@ -0,0 +1,67 @@ +package android.net.metrics + +import android.net.metrics.DhcpErrorEvent.errorCodeWithOption +import android.net.metrics.DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.internal.util.TestUtils.parcelingRoundTrip +import java.lang.reflect.Modifier +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +private const val TEST_ERROR_CODE = 12345 +/** + * DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java) + */ +private const val DHCP_SUBNET_MASK = 1 + +@RunWith(AndroidJUnit4::class) +@SmallTest +class DhcpErrorEventTest { + + @Test + fun testConstructor() { + val event = DhcpErrorEvent(TEST_ERROR_CODE) + assertEquals(TEST_ERROR_CODE, event.errorCode) + } + + @Test + fun testParcelUnparcel() { + val event = DhcpErrorEvent(TEST_ERROR_CODE) + val parceled = parcelingRoundTrip(event) + assertEquals(TEST_ERROR_CODE, parceled.errorCode) + } + + @Test + fun testErrorCodeWithOption() { + val errorCode = errorCodeWithOption(DHCP_INVALID_OPTION_LENGTH, DHCP_SUBNET_MASK); + assertTrue((DHCP_INVALID_OPTION_LENGTH and errorCode) == DHCP_INVALID_OPTION_LENGTH); + assertTrue((DHCP_SUBNET_MASK and errorCode) == DHCP_SUBNET_MASK); + } + + @Test + fun testToString() { + val names = listOf("L2_ERROR", "L3_ERROR", "L4_ERROR", "DHCP_ERROR", "MISC_ERROR") + val errorFields = DhcpErrorEvent::class.java.declaredFields.filter { + it.type == Int::class.javaPrimitiveType + && Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers) + && it.name !in names + } + + errorFields.forEach { + val intValue = it.getInt(null) + val stringValue = DhcpErrorEvent(intValue).toString() + assertTrue("Invalid string for error 0x%08X (field %s): %s".format(intValue, it.name, + stringValue), + stringValue.contains(it.name)) + } + } + + @Test + fun testToString_InvalidErrorCode() { + assertNotNull(DhcpErrorEvent(TEST_ERROR_CODE).toString()) + } +} \ No newline at end of file diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java index e0b722761c..583d3fd536 100644 --- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java +++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java @@ -79,7 +79,7 @@ public final class TcpKeepalivePacketDataTest { assertEquals(testInfo.tos, resultData.ipTos); assertEquals(testInfo.ttl, resultData.ipTtl); - TestUtils.assertParcelingIsLossless(resultData, TcpKeepalivePacketData.CREATOR); + TestUtils.assertParcelingIsLossless(resultData); final byte[] packet = resultData.getPacket(); // IP version and IHL From 8cf997d1c141e3387c67654254d5fcab02b0f2b1 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 23 Apr 2019 22:48:59 -0700 Subject: [PATCH 064/130] Move NattKeepalivePacketData out of the framework For implementing parcelable interface for NattKeepalivePacketData. Move this class out of framework.jar and move to services.jar This class is used in telephony-common.jar and it also loads service.jar. Bug: 33530442 Test: - build pass - atest NetworkStackTests - atest ConnectivityServiceTest Change-Id: Ie1d02bb7bccb76415cf71824147466cabf6b88b6 Merged-In: Ie1d02bb7bccb76415cf71824147466cabf6b88b6 Merged-In: Idf7c25b6b553d8c0cc4ef2ea8193438480420fb4 (cherry picked from commit 58a1f931eba8716c4a630863f658b070cda623de) --- .../net}/java/android/net/NattKeepalivePacketData.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {core => services/net}/java/android/net/NattKeepalivePacketData.java (100%) diff --git a/core/java/android/net/NattKeepalivePacketData.java b/services/net/java/android/net/NattKeepalivePacketData.java similarity index 100% rename from core/java/android/net/NattKeepalivePacketData.java rename to services/net/java/android/net/NattKeepalivePacketData.java From 311bac9b688639e5cda04f89ffa1bf24a35bc7ba Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 23 Apr 2019 22:17:16 +0800 Subject: [PATCH 065/130] Add AIDL parcelable for NattKeepalivePacketData Bug: 33530442 Test: atest FrameworksNetTests Change-Id: I9b9a51dc5dc06c90229fb36c34c24258991c4146 Merged-In: I9b9a51dc5dc06c90229fb36c34c24258991c4146 (cherry picked from commit 76985bd9a5577fb905e45b20513661ee10c1f44f) --- .../android/net/NattKeepalivePacketData.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/services/net/java/android/net/NattKeepalivePacketData.java b/services/net/java/android/net/NattKeepalivePacketData.java index 5c55a98b87..06838fe655 100644 --- a/services/net/java/android/net/NattKeepalivePacketData.java +++ b/services/net/java/android/net/NattKeepalivePacketData.java @@ -19,8 +19,10 @@ package android.net; import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; import static android.net.SocketKeepalive.ERROR_INVALID_PORT; +import android.annotation.NonNull; import android.net.SocketKeepalive.InvalidPacketException; import android.net.util.IpUtils; +import android.os.Parcelable; import android.system.OsConstants; import java.net.Inet4Address; @@ -29,8 +31,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; /** @hide */ -public final class NattKeepalivePacketData extends KeepalivePacketData { - +public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable { // This should only be constructed via static factory methods, such as // nattKeepalivePacket private NattKeepalivePacketData(InetAddress srcAddress, int srcPort, @@ -77,4 +78,18 @@ public final class NattKeepalivePacketData extends KeepalivePacketData { return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array()); } + + /** + * Convert this NattKeepalivePacketData to a NattKeepalivePacketDataParcelable. + */ + @NonNull + public NattKeepalivePacketDataParcelable toStableParcelable() { + final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable(); + + parcel.srcAddress = srcAddress.getAddress(); + parcel.srcPort = srcPort; + parcel.dstAddress = dstAddress.getAddress(); + parcel.dstPort = dstPort; + return parcel; + } } From 193f1686ca8422c5f9efd3bfa30821ce0625ff9a Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Mon, 29 Apr 2019 09:20:30 -0700 Subject: [PATCH 066/130] Add Network, NetworkCapabilities, StaticIpConfiguration common test cases Bug: 129200415 Bug: 129200142 Bug: 129200418 Test: atest FrameworksNetTests Test: atest CtsNetTestCases: added tests pass Change-Id: I688e200a83301ee62710445fa38292c33985fe1b Merged-In: I49c35541eb21e91f8c36215456df703d2fe70d2c Merged-In: I688e200a83301ee62710445fa38292c33985fe1b (cherry picked from commit 847dc65677b858146b505d4879a44ddd319180e2) --- .../android/net/NetworkCapabilitiesTest.java | 18 ++++++ .../common/java/android/net/NetworkTest.java | 8 +++ .../net/StaticIpConfigurationTest.java | 58 ++++++++++++++++++- 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java index ad76388b3c..6bc7c1bb30 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java @@ -33,6 +33,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES; @@ -585,4 +587,20 @@ public class NetworkCapabilitiesTest { nc2.set(nc1); // Overwrites, as opposed to combineCapabilities assertEquals(nc1, nc2); } + + @Test + public void testGetTransportTypes() { + final NetworkCapabilities nc = new NetworkCapabilities(); + nc.addTransportType(TRANSPORT_CELLULAR); + nc.addTransportType(TRANSPORT_WIFI); + nc.addTransportType(TRANSPORT_VPN); + nc.addTransportType(TRANSPORT_TEST); + + final int[] transportTypes = nc.getTransportTypes(); + assertEquals(4, transportTypes.length); + assertEquals(TRANSPORT_CELLULAR, transportTypes[0]); + assertEquals(TRANSPORT_WIFI, transportTypes[1]); + assertEquals(TRANSPORT_VPN, transportTypes[2]); + assertEquals(TRANSPORT_TEST, transportTypes[3]); + } } diff --git a/tests/net/common/java/android/net/NetworkTest.java b/tests/net/common/java/android/net/NetworkTest.java index 0bee7cd29d..bef66b27df 100644 --- a/tests/net/common/java/android/net/NetworkTest.java +++ b/tests/net/common/java/android/net/NetworkTest.java @@ -155,4 +155,12 @@ public class NetworkTest { private static void assertNotEqual(T t1, T t2) { assertFalse(Objects.equals(t1, t2)); } + + @Test + public void testGetPrivateDnsBypassingCopy() { + final Network copy = mNetwork.getPrivateDnsBypassingCopy(); + assertEquals(mNetwork.netId, copy.netId); + assertNotEqual(copy.netId, copy.getNetIdForResolv()); + assertNotEqual(mNetwork.getNetIdForResolv(), copy.getNetIdForResolv()); + } } diff --git a/tests/net/common/java/android/net/StaticIpConfigurationTest.java b/tests/net/common/java/android/net/StaticIpConfigurationTest.java index 8449ca76d5..5096be221c 100644 --- a/tests/net/common/java/android/net/StaticIpConfigurationTest.java +++ b/tests/net/common/java/android/net/StaticIpConfigurationTest.java @@ -31,7 +31,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Objects; @RunWith(AndroidJUnit4.class) @@ -46,6 +48,7 @@ public class StaticIpConfigurationTest { private static final InetAddress DNS2 = IpAddress("8.8.4.4"); private static final InetAddress DNS3 = IpAddress("4.2.2.2"); private static final String IFACE = "eth0"; + private static final String FAKE_DOMAINS = "google.com"; private static InetAddress IpAddress(String addr) { return InetAddress.parseNumericAddress(addr); @@ -69,7 +72,7 @@ public class StaticIpConfigurationTest { s.dnsServers.add(DNS1); s.dnsServers.add(DNS2); s.dnsServers.add(DNS3); - s.domains = "google.com"; + s.domains = FAKE_DOMAINS; return s; } @@ -178,8 +181,8 @@ public class StaticIpConfigurationTest { expected.addDnsServer(DNS3); assertEquals(expected, s.toLinkProperties(IFACE)); - s.domains = "google.com"; - expected.setDomains("google.com"); + s.domains = FAKE_DOMAINS; + expected.setDomains(FAKE_DOMAINS); assertEquals(expected, s.toLinkProperties(IFACE)); s.gateway = null; @@ -218,4 +221,53 @@ public class StaticIpConfigurationTest { StaticIpConfiguration s2 = passThroughParcel(s); assertEquals(s, s2); } + + @Test + public void testBuilder() { + final ArrayList dnsServers = new ArrayList<>(); + dnsServers.add(DNS1); + + final StaticIpConfiguration s = new StaticIpConfiguration.Builder() + .setIpAddress(ADDR) + .setGateway(GATEWAY) + .setDomains(FAKE_DOMAINS) + .setDnsServers(dnsServers) + .build(); + + assertEquals(s.ipAddress, s.getIpAddress()); + assertEquals(ADDR, s.getIpAddress()); + assertEquals(s.gateway, s.getGateway()); + assertEquals(GATEWAY, s.getGateway()); + assertEquals(s.domains, s.getDomains()); + assertEquals(FAKE_DOMAINS, s.getDomains()); + assertTrue(s.dnsServers.equals(s.getDnsServers())); + assertEquals(1, s.getDnsServers().size()); + assertEquals(DNS1, s.getDnsServers().get(0)); + } + + @Test + public void testAddDnsServers() { + final StaticIpConfiguration s = new StaticIpConfiguration((StaticIpConfiguration) null); + checkEmpty(s); + + s.addDnsServer(DNS1); + assertEquals(1, s.getDnsServers().size()); + assertEquals(DNS1, s.getDnsServers().get(0)); + + s.addDnsServer(DNS2); + s.addDnsServer(DNS3); + assertEquals(3, s.getDnsServers().size()); + assertEquals(DNS2, s.getDnsServers().get(1)); + assertEquals(DNS3, s.getDnsServers().get(2)); + } + + @Test + public void testGetRoutes() { + final StaticIpConfiguration s = makeTestObject(); + final List routeInfoList = s.getRoutes(IFACE); + + assertEquals(2, routeInfoList.size()); + assertEquals(new RouteInfo(ADDR, (InetAddress) null, IFACE), routeInfoList.get(0)); + assertEquals(new RouteInfo((IpPrefix) null, GATEWAY, IFACE), routeInfoList.get(1)); + } } From 5de4520591a8b5b982c2584f83f049175d11f369 Mon Sep 17 00:00:00 2001 From: Mark Chien Date: Mon, 29 Apr 2019 09:46:04 -0700 Subject: [PATCH 067/130] Support adding NATT keepalive packet filter Support adding NATT keepalive packet filter to APF filter. Generating APF program will be addressed in another CL. Bug: 33530442 Test: - atest NetworkStackTests - atest FrameworksNetTests Change-Id: I403cd14ac9aa6b001c4e580abbb33a615931a192 Merged-In: Idaa7238a5c9acdae9f6cff13095ee9436c7c92c8 (cherry picked from commit 038c11d564452c9e08f25119423049339ff93c57) --- .../com/android/server/ConnectivityServiceTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c15775fc47..363ac9ce1d 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -567,6 +567,16 @@ public class ConnectivityServiceTest { protected void preventAutomaticReconnect() { mPreventReconnectReceived.open(); } + + @Override + protected void addKeepalivePacketFilter(Message msg) { + Log.i(TAG, "Add keepalive packet filter."); + } + + @Override + protected void removeKeepalivePacketFilter(Message msg) { + Log.i(TAG, "Remove keepalive packet filter."); + } }; assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId); From 454cf032a8483a327bcee3e2b9fcd3bd430308a0 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Thu, 2 May 2019 01:24:32 -0700 Subject: [PATCH 068/130] Add CTS API coverage for APIs which are used by NetworkStack Bug: 129200003 Bug: 129200292 Bug: 129199996 Bug: 129200261 Bug: 129200513 Bug: 129200316 Bug: 129200589 Bug: 129200181 Bug: 129200669 Bug: 129200504 Bug: 129200478 Test: atest FrameworksNetTests Test: atest CtsNetTestCases: added tests pass Change-Id: I0fed0664c1eb7b07c890efffb71ef589f65eec80 Merged-In: Id3f0d1c19a76c7987b69e449203fc50423f5e531 Merged-In: I0fed0664c1eb7b07c890efffb71ef589f65eec80 (cherry picked from commit 8c6a07de57680d7d2db75fada3e3ab04c27fa62f) --- tests/net/common/Android.bp | 1 + .../java/android/net/CaptivePortalTest.java | 90 ++++++++++ .../net/metrics/ApfProgramEventTest.kt | 79 +++++++++ .../java/android/net/metrics/ApfStatsTest.kt | 64 +++++++ .../android/net/metrics/DhcpErrorEventTest.kt | 4 +- .../net/metrics/IpConnectivityLogTest.java | 161 ++++++++++++++++++ .../net/metrics/IpReachabilityEventTest.kt | 45 +++++ .../java/android/net/metrics/RaEventTest.kt | 79 +++++++++ .../net/metrics/ValidationProbeEventTest.kt | 79 +++++++++ .../IpConnectivityMetricsTest.java | 83 --------- 10 files changed, 599 insertions(+), 86 deletions(-) create mode 100644 tests/net/common/java/android/net/CaptivePortalTest.java create mode 100644 tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt create mode 100644 tests/net/common/java/android/net/metrics/ApfStatsTest.kt create mode 100644 tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java create mode 100644 tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt create mode 100644 tests/net/common/java/android/net/metrics/RaEventTest.kt create mode 100644 tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp index 3b2e34a159..07525a6ea4 100644 --- a/tests/net/common/Android.bp +++ b/tests/net/common/Android.bp @@ -23,6 +23,7 @@ java_library { "androidx.test.rules", "frameworks-net-testutils", "junit", + "mockito-target-minus-junit4", ], libs: [ "android.test.base.stubs", diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java new file mode 100644 index 0000000000..eed7159ffd --- /dev/null +++ b/tests/net/common/java/android/net/CaptivePortalTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 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 org.junit.Assert.assertEquals; + +import android.os.RemoteException; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class CaptivePortalTest { + private static final int DEFAULT_TIMEOUT_MS = 5000; + private static final String TEST_PACKAGE_NAME = "com.google.android.test"; + + private final class MyCaptivePortalImpl extends ICaptivePortal.Stub { + int mCode = -1; + String mPackageName = null; + + @Override + public void appResponse(final int response) throws RemoteException { + mCode = response; + } + + @Override + public void logEvent(int eventId, String packageName) throws RemoteException { + mCode = eventId; + mPackageName = packageName; + } + } + + private interface TestFunctor { + void useCaptivePortal(CaptivePortal o); + } + + private MyCaptivePortalImpl runCaptivePortalTest(TestFunctor f) { + final MyCaptivePortalImpl cp = new MyCaptivePortalImpl(); + f.useCaptivePortal(new CaptivePortal(cp.asBinder())); + return cp; + } + + @Test + public void testReportCaptivePortalDismissed() { + final MyCaptivePortalImpl result = + runCaptivePortalTest(c -> c.reportCaptivePortalDismissed()); + assertEquals(result.mCode, CaptivePortal.APP_RETURN_DISMISSED); + } + + @Test + public void testIgnoreNetwork() { + final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.ignoreNetwork()); + assertEquals(result.mCode, CaptivePortal.APP_RETURN_UNWANTED); + } + + @Test + public void testUseNetwork() { + final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.useNetwork()); + assertEquals(result.mCode, CaptivePortal.APP_RETURN_WANTED_AS_IS); + } + + @Test + public void testLogEvent() { + final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent( + MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY, + TEST_PACKAGE_NAME)); + assertEquals(result.mCode, MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY); + assertEquals(result.mPackageName, TEST_PACKAGE_NAME); + } +} diff --git a/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt b/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt new file mode 100644 index 0000000000..8d055c93c4 --- /dev/null +++ b/tests/net/common/java/android/net/metrics/ApfProgramEventTest.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 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.metrics; + +import android.os.Parcelable +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.internal.util.ParcelableTestUtil +import com.android.internal.util.TestUtils +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class ApfProgramEventTest { + private fun testParcel(obj: T, fieldCount: Int) { + ParcelableTestUtil.assertFieldCountEquals(fieldCount, obj::class.java) + TestUtils.assertParcelingIsLossless(obj) + } + + private infix fun Int.hasFlag(flag: Int) = (this and (1 shl flag)) != 0 + + @Test + fun testBuilderAndParcel() { + val apfProgramEvent = ApfProgramEvent.Builder() + .setLifetime(1) + .setActualLifetime(2) + .setFilteredRas(3) + .setCurrentRas(4) + .setProgramLength(5) + .setFlags(true, true) + .build() + + assertEquals(1, apfProgramEvent.lifetime) + assertEquals(2, apfProgramEvent.actualLifetime) + assertEquals(3, apfProgramEvent.filteredRas) + assertEquals(4, apfProgramEvent.currentRas) + assertEquals(5, apfProgramEvent.programLength) + assertEquals(ApfProgramEvent.flagsFor(true, true), apfProgramEvent.flags) + + testParcel(apfProgramEvent, 6) + } + + @Test + fun testFlagsFor() { + var flags = ApfProgramEvent.flagsFor(false, false) + assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS) + assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON) + + flags = ApfProgramEvent.flagsFor(true, false) + assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS) + assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON) + + flags = ApfProgramEvent.flagsFor(false, true) + assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS) + assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON) + + flags = ApfProgramEvent.flagsFor(true, true) + assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS) + assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON) + } +} diff --git a/tests/net/common/java/android/net/metrics/ApfStatsTest.kt b/tests/net/common/java/android/net/metrics/ApfStatsTest.kt new file mode 100644 index 0000000000..f8eb40cccd --- /dev/null +++ b/tests/net/common/java/android/net/metrics/ApfStatsTest.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 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.metrics + +import android.os.Parcelable +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.internal.util.ParcelableTestUtil +import com.android.internal.util.TestUtils +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class ApfStatsTest { + private fun testParcel(obj: T, fieldCount: Int) { + ParcelableTestUtil.assertFieldCountEquals(fieldCount, obj::class.java) + TestUtils.assertParcelingIsLossless(obj) + } + + @Test + fun testBuilderAndParcel() { + val apfStats = ApfStats.Builder() + .setDurationMs(Long.MAX_VALUE) + .setReceivedRas(1) + .setMatchingRas(2) + .setDroppedRas(3) + .setZeroLifetimeRas(4) + .setParseErrors(5) + .setProgramUpdates(6) + .setProgramUpdatesAll(7) + .setProgramUpdatesAllowingMulticast(8) + .setMaxProgramSize(9) + .build() + + assertEquals(Long.MAX_VALUE, apfStats.durationMs) + assertEquals(1, apfStats.receivedRas) + assertEquals(2, apfStats.matchingRas) + assertEquals(3, apfStats.droppedRas) + assertEquals(4, apfStats.zeroLifetimeRas) + assertEquals(5, apfStats.parseErrors) + assertEquals(6, apfStats.programUpdates) + assertEquals(7, apfStats.programUpdatesAll) + assertEquals(8, apfStats.programUpdatesAllowingMulticast) + assertEquals(9, apfStats.maxProgramSize) + + testParcel(apfStats, 10) + } +} diff --git a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt index e19195322e..e9d5e6db1c 100644 --- a/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt +++ b/tests/net/common/java/android/net/metrics/DhcpErrorEventTest.kt @@ -13,9 +13,7 @@ import org.junit.Test import org.junit.runner.RunWith private const val TEST_ERROR_CODE = 12345 -/** - * DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java) - */ +//DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java due to it's protected) private const val DHCP_SUBNET_MASK = 1 @RunWith(AndroidJUnit4::class) diff --git a/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java b/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java new file mode 100644 index 0000000000..d4780d3a5d --- /dev/null +++ b/tests/net/common/java/android/net/metrics/IpConnectivityLogTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2019 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.metrics; + +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; + +import android.net.ConnectivityMetricsEvent; +import android.net.IIpConnectivityMetrics; +import android.net.Network; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.util.BitUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IpConnectivityLogTest { + private static final int FAKE_NET_ID = 100; + private static final int[] FAKE_TRANSPORT_TYPES = BitUtils.unpackBits(TRANSPORT_WIFI); + private static final long FAKE_TIME_STAMP = System.currentTimeMillis(); + private static final String FAKE_INTERFACE_NAME = "test"; + private static final IpReachabilityEvent FAKE_EV = + new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED); + + @Mock IIpConnectivityMetrics mMockService; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testLoggingEvents() throws Exception { + IpConnectivityLog logger = new IpConnectivityLog(mMockService); + + assertTrue(logger.log(FAKE_EV)); + assertTrue(logger.log(FAKE_TIME_STAMP, FAKE_EV)); + assertTrue(logger.log(FAKE_NET_ID, FAKE_TRANSPORT_TYPES, FAKE_EV)); + assertTrue(logger.log(new Network(FAKE_NET_ID), FAKE_TRANSPORT_TYPES, FAKE_EV)); + assertTrue(logger.log(FAKE_INTERFACE_NAME, FAKE_EV)); + assertTrue(logger.log(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID, TRANSPORT_WIFI, + FAKE_INTERFACE_NAME))); + + List got = verifyEvents(6); + assertEventsEqual(makeExpectedEvent(got.get(0).timestamp, 0, 0, null), got.get(0)); + assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, 0, 0, null), got.get(1)); + assertEventsEqual(makeExpectedEvent(got.get(2).timestamp, FAKE_NET_ID, + TRANSPORT_WIFI, null), got.get(2)); + assertEventsEqual(makeExpectedEvent(got.get(3).timestamp, FAKE_NET_ID, + TRANSPORT_WIFI, null), got.get(3)); + assertEventsEqual(makeExpectedEvent(got.get(4).timestamp, 0, 0, FAKE_INTERFACE_NAME), + got.get(4)); + assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID, + TRANSPORT_WIFI, FAKE_INTERFACE_NAME), got.get(5)); + } + + @Test + public void testLoggingEventsWithMultipleCallers() throws Exception { + IpConnectivityLog logger = new IpConnectivityLog(mMockService); + + final int nCallers = 10; + final int nEvents = 10; + for (int n = 0; n < nCallers; n++) { + final int i = n; + new Thread() { + public void run() { + for (int j = 0; j < nEvents; j++) { + assertTrue(logger.log(makeExpectedEvent( + FAKE_TIME_STAMP + i * 100 + j, + FAKE_NET_ID + i * 100 + j, + ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR, + FAKE_INTERFACE_NAME))); + } + } + }.start(); + } + + List got = verifyEvents(nCallers * nEvents, 200); + Collections.sort(got, EVENT_COMPARATOR); + Iterator iter = got.iterator(); + for (int i = 0; i < nCallers; i++) { + for (int j = 0; j < nEvents; j++) { + final long expectedTimestamp = FAKE_TIME_STAMP + i * 100 + j; + final int expectedNetId = FAKE_NET_ID + i * 100 + j; + final long expectedTransports = + ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR; + assertEventsEqual(makeExpectedEvent(expectedTimestamp, expectedNetId, + expectedTransports, FAKE_INTERFACE_NAME), iter.next()); + } + } + } + + private List verifyEvents(int n, int timeoutMs) throws Exception { + ArgumentCaptor captor = + ArgumentCaptor.forClass(ConnectivityMetricsEvent.class); + verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture()); + return captor.getAllValues(); + } + + private List verifyEvents(int n) throws Exception { + return verifyEvents(n, 10); + } + + + private ConnectivityMetricsEvent makeExpectedEvent(long timestamp, int netId, long transports, + String ifname) { + ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent(); + ev.timestamp = timestamp; + ev.data = FAKE_EV; + ev.netId = netId; + ev.transports = transports; + ev.ifname = ifname; + return ev; + } + + /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */ + private void assertEventsEqual(ConnectivityMetricsEvent expected, + ConnectivityMetricsEvent got) { + assertEquals(expected.data, got.data); + assertEquals(expected.timestamp, got.timestamp); + assertEquals(expected.netId, got.netId); + assertEquals(expected.transports, got.transports); + assertEquals(expected.ifname, got.ifname); + } + + static final Comparator EVENT_COMPARATOR = + Comparator.comparingLong((ev) -> ev.timestamp); +} diff --git a/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt b/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt new file mode 100644 index 0000000000..d76ebf67ff --- /dev/null +++ b/tests/net/common/java/android/net/metrics/IpReachabilityEventTest.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 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.metrics + +import android.os.Parcelable +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.internal.util.ParcelableTestUtil +import com.android.internal.util.TestUtils +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class IpReachabilityEventTest { + private fun testParcel(obj: T, fieldCount: Int) { + ParcelableTestUtil.assertFieldCountEquals(fieldCount, obj::class.java) + TestUtils.assertParcelingIsLossless(obj) + } + + @Test + fun testConstructorAndParcel() { + (IpReachabilityEvent.PROBE..IpReachabilityEvent.PROVISIONING_LOST_ORGANIC).forEach { + val ipReachabilityEvent = IpReachabilityEvent(it) + assertEquals(it, ipReachabilityEvent.eventType) + + testParcel(ipReachabilityEvent, 1) + } + } +} diff --git a/tests/net/common/java/android/net/metrics/RaEventTest.kt b/tests/net/common/java/android/net/metrics/RaEventTest.kt new file mode 100644 index 0000000000..f38d328442 --- /dev/null +++ b/tests/net/common/java/android/net/metrics/RaEventTest.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 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.metrics + +import android.os.Parcelable +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.internal.util.ParcelableTestUtil +import com.android.internal.util.TestUtils +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +private const val NO_LIFETIME: Long = -1L + +@RunWith(AndroidJUnit4::class) +@SmallTest +class RaEventTest { + private fun testParcel(obj: T, fieldCount: Int) { + ParcelableTestUtil.assertFieldCountEquals(fieldCount, obj::class.java) + TestUtils.assertParcelingIsLossless(obj) + } + + @Test + fun testConstructorAndParcel() { + var raEvent = RaEvent.Builder().build() + assertEquals(NO_LIFETIME, raEvent.routerLifetime) + assertEquals(NO_LIFETIME, raEvent.prefixValidLifetime) + assertEquals(NO_LIFETIME, raEvent.prefixPreferredLifetime) + assertEquals(NO_LIFETIME, raEvent.routeInfoLifetime) + assertEquals(NO_LIFETIME, raEvent.rdnssLifetime) + assertEquals(NO_LIFETIME, raEvent.dnsslLifetime) + + raEvent = RaEvent.Builder() + .updateRouterLifetime(1) + .updatePrefixValidLifetime(2) + .updatePrefixPreferredLifetime(3) + .updateRouteInfoLifetime(4) + .updateRdnssLifetime(5) + .updateDnsslLifetime(6) + .build() + assertEquals(1, raEvent.routerLifetime) + assertEquals(2, raEvent.prefixValidLifetime) + assertEquals(3, raEvent.prefixPreferredLifetime) + assertEquals(4, raEvent.routeInfoLifetime) + assertEquals(5, raEvent.rdnssLifetime) + assertEquals(6, raEvent.dnsslLifetime) + + raEvent = RaEvent.Builder() + .updateRouterLifetime(Long.MIN_VALUE) + .updateRouterLifetime(Long.MAX_VALUE) + .build() + assertEquals(Long.MIN_VALUE, raEvent.routerLifetime) + + raEvent = RaEvent(1, 2, 3, 4, 5, 6) + assertEquals(1, raEvent.routerLifetime) + assertEquals(2, raEvent.prefixValidLifetime) + assertEquals(3, raEvent.prefixPreferredLifetime) + assertEquals(4, raEvent.routeInfoLifetime) + assertEquals(5, raEvent.rdnssLifetime) + assertEquals(6, raEvent.dnsslLifetime) + + testParcel(raEvent, 6) + } +} diff --git a/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt b/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt new file mode 100644 index 0000000000..c0cef8fe91 --- /dev/null +++ b/tests/net/common/java/android/net/metrics/ValidationProbeEventTest.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 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.metrics + +import android.os.Parcelable +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.internal.util.ParcelableTestUtil +import com.android.internal.util.TestUtils +import java.lang.reflect.Modifier +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +private const val FIRST_VALIDATION: Int = 1 shl 8 +private const val REVALIDATION: Int = 2 shl 8 + +@RunWith(AndroidJUnit4::class) +@SmallTest +class ValidationProbeEventTest { + private fun testParcel(obj: T, fieldCount: Int) { + ParcelableTestUtil.assertFieldCountEquals(fieldCount, obj::class.java) + TestUtils.assertParcelingIsLossless(obj) + } + + private infix fun Int.hasType(type: Int) = (type and this) == type + + @Test + fun testBuilderAndParcel() { + var validationProbeEvent = ValidationProbeEvent.Builder() + .setProbeType(ValidationProbeEvent.PROBE_DNS, false).build() + + assertTrue(validationProbeEvent.probeType hasType REVALIDATION) + + validationProbeEvent = ValidationProbeEvent.Builder() + .setDurationMs(Long.MAX_VALUE) + .setProbeType(ValidationProbeEvent.PROBE_DNS, true) + .setReturnCode(ValidationProbeEvent.DNS_SUCCESS) + .build() + + assertEquals(Long.MAX_VALUE, validationProbeEvent.durationMs) + assertTrue(validationProbeEvent.probeType hasType ValidationProbeEvent.PROBE_DNS) + assertTrue(validationProbeEvent.probeType hasType FIRST_VALIDATION) + assertEquals(ValidationProbeEvent.DNS_SUCCESS, validationProbeEvent.returnCode) + + testParcel(validationProbeEvent, 3) + } + + @Test + fun testGetProbeName() { + val probeFields = ValidationProbeEvent::class.java.declaredFields.filter { + it.type == Int::class.javaPrimitiveType + && Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers) + && it.name.contains("PROBE") + } + + probeFields.forEach { + val intValue = it.getInt(null) + val stringValue = ValidationProbeEvent.getProbeName(intValue) + assertEquals(it.name, stringValue) + } + + } +} diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java index d5b2c87ffe..3a071667a5 100644 --- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java +++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java @@ -21,11 +21,8 @@ import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; @@ -59,16 +56,11 @@ import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; @RunWith(AndroidJUnit4.class) @SmallTest @@ -97,48 +89,6 @@ public class IpConnectivityMetricsTest { mService.mNetdListener = mNetdListener; } - @Test - public void testLoggingEvents() throws Exception { - IpConnectivityLog logger = new IpConnectivityLog(mMockService); - - assertTrue(logger.log(1, FAKE_EV)); - assertTrue(logger.log(2, FAKE_EV)); - assertTrue(logger.log(3, FAKE_EV)); - - List got = verifyEvents(3); - assertEventsEqual(expectedEvent(1), got.get(0)); - assertEventsEqual(expectedEvent(2), got.get(1)); - assertEventsEqual(expectedEvent(3), got.get(2)); - } - - @Test - public void testLoggingEventsWithMultipleCallers() throws Exception { - IpConnectivityLog logger = new IpConnectivityLog(mMockService); - - final int nCallers = 10; - final int nEvents = 10; - for (int n = 0; n < nCallers; n++) { - final int i = n; - new Thread() { - public void run() { - for (int j = 0; j < nEvents; j++) { - assertTrue(logger.log(1 + i * 100 + j, FAKE_EV)); - } - } - }.start(); - } - - List got = verifyEvents(nCallers * nEvents, 200); - Collections.sort(got, EVENT_COMPARATOR); - Iterator iter = got.iterator(); - for (int i = 0; i < nCallers; i++) { - for (int j = 0; j < nEvents; j++) { - int expectedTimestamp = 1 + i * 100 + j; - assertEventsEqual(expectedEvent(expectedTimestamp), iter.next()); - } - } - } - @Test public void testBufferFlushing() { String output1 = getdump("flush"); @@ -653,16 +603,7 @@ public class IpConnectivityMetricsTest { return nai; } - List verifyEvents(int n, int timeoutMs) throws Exception { - ArgumentCaptor captor = - ArgumentCaptor.forClass(ConnectivityMetricsEvent.class); - verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture()); - return captor.getAllValues(); - } - List verifyEvents(int n) throws Exception { - return verifyEvents(n, 10); - } static void verifySerialization(String want, String output) { try { @@ -674,28 +615,4 @@ public class IpConnectivityMetricsTest { fail(e.toString()); } } - - static String joinLines(String ... elems) { - StringBuilder b = new StringBuilder(); - for (String s : elems) { - b.append(s).append("\n"); - } - return b.toString(); - } - - static ConnectivityMetricsEvent expectedEvent(int timestamp) { - ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent(); - ev.timestamp = timestamp; - ev.data = FAKE_EV; - return ev; - } - - /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */ - static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) { - assertEquals(expected.timestamp, got.timestamp); - assertEquals(expected.data, got.data); - } - - static final Comparator EVENT_COMPARATOR = - Comparator.comparingLong((ev) -> ev.timestamp); } From 53578de5d10c186771a66f56e4f5fa9be4c215f3 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Thu, 2 May 2019 01:54:50 -0700 Subject: [PATCH 069/130] Correct buffer size limitation for DnsResolver API Bug: 131055651 Test: atest DnsResolverTest (cherry picked from commit f6726c2c5456887aaebe3f821a86a83bbed92f3d) Change-Id: I69ad9428ddfb70437e47ef4740930a97aece69d9 --- core/jni/android_net_NetUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 28c59db6b9..c5fc9b3628 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -49,8 +49,8 @@ int ifc_disable(const char *ifname); namespace android { constexpr int MAXPACKETSIZE = 8 * 1024; -// FrameworkListener limits the size of commands to 1024 bytes. TODO: fix this. -constexpr int MAXCMDSIZE = 1024; +// FrameworkListener limits the size of commands to 4096 bytes. +constexpr int MAXCMDSIZE = 4096; static void throwErrnoException(JNIEnv* env, const char* functionName, int error) { ScopedLocalRef detailMessage(env, env->NewStringUTF(functionName)); From d7be3aa1d2e53f90f713b42efc27108dd0925286 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 8 Nov 2018 19:45:34 -0800 Subject: [PATCH 070/130] Add IPsec checks for IPSEC_TUNNEL feature This patch adds checks to ensure that the IPSEC_TUNNEL feature flag is enabled. Bug: 117183273 Test: Compiles & tests passing Change-Id: I2699dda29e1eed139bc6fd1b70071e5ab33cad88 --- .../server/IpSecServiceParameterizedTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java index 7c40adfac0..71b72b84de 100644 --- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java @@ -32,6 +32,7 @@ import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.net.INetd; import android.net.IpSecAlgorithm; import android.net.IpSecConfig; @@ -57,6 +58,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import java.net.Inet4Address; import java.net.Socket; import java.util.Arrays; import java.util.Collection; @@ -118,6 +120,11 @@ public class IpSecServiceParameterizedTest { } } + @Override + public PackageManager getPackageManager() { + return mMockPkgMgr; + } + @Override public void enforceCallingOrSelfPermission(String permission, String message) { if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) { @@ -128,6 +135,7 @@ public class IpSecServiceParameterizedTest { }; INetd mMockNetd; + PackageManager mMockPkgMgr; IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig; IpSecService mIpSecService; Network fakeNetwork = new Network(0xAB); @@ -152,11 +160,16 @@ public class IpSecServiceParameterizedTest { @Before public void setUp() throws Exception { mMockNetd = mock(INetd.class); + mMockPkgMgr = mock(PackageManager.class); mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class); mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig); // Injecting mock netd when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd); + + // PackageManager should always return true (feature flag tests in IpSecServiceTest) + when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true); + // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED. when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage"))) .thenReturn(AppOpsManager.MODE_ALLOWED); @@ -709,4 +722,18 @@ public class IpSecServiceParameterizedTest { } catch (SecurityException expected) { } } + + @Test + public void testFeatureFlagVerification() throws Exception { + when(mMockPkgMgr.hasSystemFeature(eq(PackageManager.FEATURE_IPSEC_TUNNELS))) + .thenReturn(false); + + try { + String addr = Inet4Address.getLoopbackAddress().getHostAddress(); + mIpSecService.createTunnelInterface( + addr, addr, new Network(0), new Binder(), "blessedPackage"); + fail("Expected UnsupportedOperationException for disabled feature"); + } catch (UnsupportedOperationException expected) { + } + } } From 2f9a465841b5d8afa4cff4af8ffdabcea63cbaa1 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Tue, 16 Apr 2019 15:07:55 -0700 Subject: [PATCH 071/130] [CS] Unregister callback as part of onUnavailable dispatch The onUnavailable semantics promise that it is equivalent to calling the unregister callback method. But - it doesn't unregister the callback allowing it to be reused. Fixed. Additionally, modified the unregisterNetworkCallback method to not fail on duplicate unregistration (since a callback could now self unregister). Instead simply print a log. Bug: 130651445 Test: atest ConnectivityServiceTest Merged-In: I4c54b003a733eb0b1e4fd8674ed13081b1bef8e3 Change-Id: I4c54b003a733eb0b1e4fd8674ed13081b1bef8e3 --- core/java/android/net/ConnectivityManager.java | 10 ++++++++-- .../com/android/server/ConnectivityServiceTest.java | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 0e10de8c4e..a69ca99500 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -3449,6 +3449,10 @@ public class ConnectivityManager { final NetworkCallback callback; synchronized (sCallbacks) { callback = sCallbacks.get(request); + if (message.what == CALLBACK_UNAVAIL) { + sCallbacks.remove(request); + callback.networkRequest = ALREADY_UNREGISTERED; + } } if (DBG) { Log.d(TAG, getCallbackName(message.what) + " for network " + network); @@ -3995,8 +3999,10 @@ public class ConnectivityManager { synchronized (sCallbacks) { Preconditions.checkArgument(networkCallback.networkRequest != null, "NetworkCallback was not registered"); - Preconditions.checkArgument(networkCallback.networkRequest != ALREADY_UNREGISTERED, - "NetworkCallback was already unregistered"); + if (networkCallback.networkRequest == ALREADY_UNREGISTERED) { + Log.d(TAG, "NetworkCallback was already unregistered"); + return; + } for (Map.Entry e : sCallbacks.entrySet()) { if (e.getValue() == networkCallback) { reqs.add(e.getKey()); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 363ac9ce1d..0ef56e553a 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -3854,6 +3854,9 @@ public class ConnectivityServiceTest { networkCallback.expectCallback(CallbackState.UNAVAILABLE, null); testFactory.waitForRequests(); + // unregister network callback - a no-op, but should not fail + mCm.unregisterNetworkCallback(networkCallback); + testFactory.unregister(); handlerThread.quit(); } From 015598ea52c3db8e1dc78a144febefac079e6705 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 9 May 2019 04:55:13 -0700 Subject: [PATCH 072/130] adopt non-blocking method to obtain the IpMemoryStore service. Bug: 131133347 Test: atest FrameworksNetTests Merged-In: I7de4f23370bdf9c9df5e74ed074c794080d93d95 Merged-In: If0d43f21710ca31149610d3e6a5f0d7e4acc11a2 Change-Id: If0d43f21710ca31149610d3e6a5f0d7e4acc11a2 (cherry picked from commit c4e4fd7beeda36c84548c7bb4a16312f20bdf188) --- .../java/android/net/IpMemoryStoreTest.java | 279 +++++++++++++++++- .../ipmemorystore/NetworkAttributesTest.java | 2 +- 2 files changed, 265 insertions(+), 16 deletions(-) diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java index 18c6768894..8ff2de9777 100644 --- a/tests/net/java/android/net/IpMemoryStoreTest.java +++ b/tests/net/java/android/net/IpMemoryStoreTest.java @@ -16,10 +16,26 @@ package android.net; -import static org.mockito.ArgumentMatchers.any; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.content.Context; +import android.net.ipmemorystore.Blob; +import android.net.ipmemorystore.IOnStatusListener; +import android.net.ipmemorystore.NetworkAttributes; +import android.net.ipmemorystore.NetworkAttributesParcelable; +import android.net.ipmemorystore.Status; +import android.os.RemoteException; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -27,28 +43,57 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.net.UnknownHostException; +import java.util.Arrays; + @RunWith(AndroidJUnit4.class) @SmallTest public class IpMemoryStoreTest { + private static final String TAG = IpMemoryStoreTest.class.getSimpleName(); + private static final String TEST_CLIENT_ID = "testClientId"; + private static final String TEST_DATA_NAME = "testData"; + private static final String TEST_OTHER_DATA_NAME = TEST_DATA_NAME + "Other"; + private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12, + -128, 0, 89, 112, 91, -34 }; + private static final NetworkAttributes TEST_NETWORK_ATTRIBUTES = buildTestNetworkAttributes( + "hint", 219); + @Mock Context mMockContext; @Mock NetworkStackClient mNetworkStackClient; @Mock IIpMemoryStore mMockService; + @Mock + IOnStatusListener mIOnStatusListener; IpMemoryStore mStore; + @Captor + ArgumentCaptor mCbCaptor; + @Captor + ArgumentCaptor mNapCaptor; + @Before public void setUp() { MockitoAnnotations.initMocks(this); - doAnswer(invocation -> { - ((IIpMemoryStoreCallbacks) invocation.getArgument(0)) - .onIpMemoryStoreFetched(mMockService); - return null; - }).when(mNetworkStackClient).fetchIpMemoryStore(any()); + } + + private void startIpMemoryStore(boolean supplyService) { + if (supplyService) { + doAnswer(invocation -> { + ((IIpMemoryStoreCallbacks) invocation.getArgument(0)) + .onIpMemoryStoreFetched(mMockService); + return null; + }).when(mNetworkStackClient).fetchIpMemoryStore(any()); + } else { + doNothing().when(mNetworkStackClient).fetchIpMemoryStore(mCbCaptor.capture()); + } mStore = new IpMemoryStore(mMockContext) { @Override protected NetworkStackClient getNetworkStackClient() { @@ -57,24 +102,228 @@ public class IpMemoryStoreTest { }; } - @Test - public void testNetworkAttributes() { - // TODO : implement this + private static NetworkAttributes buildTestNetworkAttributes(String hint, int mtu) { + return new NetworkAttributes.Builder() + .setGroupHint(hint) + .setMtu(mtu) + .build(); } @Test - public void testPrivateData() { - // TODO : implement this + public void testNetworkAttributes() throws Exception { + startIpMemoryStore(true); + final String l2Key = "fakeKey"; + + mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, + status -> { + assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); + }); + verify(mMockService, times(1)).storeNetworkAttributes(eq(l2Key), + mNapCaptor.capture(), any()); + assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); + + mStore.retrieveNetworkAttributes(l2Key, + (status, key, attr) -> { + assertTrue("Retrieve network attributes not successful : " + + status.resultCode, status.isSuccess()); + assertEquals(l2Key, key); + assertEquals(TEST_NETWORK_ATTRIBUTES, attr); + }); + + verify(mMockService, times(1)).retrieveNetworkAttributes(eq(l2Key), any()); } @Test - public void testFindL2Key() { - // TODO : implement this + public void testPrivateData() throws RemoteException { + startIpMemoryStore(true); + final Blob b = new Blob(); + b.data = TEST_BLOB_DATA; + final String l2Key = "fakeKey"; + + mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b, + status -> { + assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); + }); + verify(mMockService, times(1)).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME), + eq(b), any()); + + mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME, + (status, key, name, data) -> { + assertTrue("Retrieve blob status not successful : " + status.resultCode, + status.isSuccess()); + assertEquals(l2Key, key); + assertEquals(name, TEST_DATA_NAME); + assertTrue(Arrays.equals(b.data, data.data)); + }); + verify(mMockService, times(1)).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID), + eq(TEST_OTHER_DATA_NAME), any()); } @Test - public void testIsSameNetwork() { - // TODO : implement this + public void testFindL2Key() + throws UnknownHostException, RemoteException, Exception { + startIpMemoryStore(true); + final String l2Key = "fakeKey"; + + mStore.findL2Key(TEST_NETWORK_ATTRIBUTES, + (status, key) -> { + assertTrue("Retrieve network sameness not successful : " + status.resultCode, + status.isSuccess()); + assertEquals(l2Key, key); + }); + verify(mMockService, times(1)).findL2Key(mNapCaptor.capture(), any()); + assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); } + @Test + public void testIsSameNetwork() throws UnknownHostException, RemoteException { + startIpMemoryStore(true); + final String l2Key1 = "fakeKey1"; + final String l2Key2 = "fakeKey2"; + + mStore.isSameNetwork(l2Key1, l2Key2, + (status, answer) -> { + assertFalse("Retrieve network sameness suspiciously successful : " + + status.resultCode, status.isSuccess()); + assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode); + assertNull(answer); + }); + verify(mMockService, times(1)).isSameNetwork(eq(l2Key1), eq(l2Key2), any()); + } + + @Test + public void testEnqueuedIpMsRequests() throws Exception { + startIpMemoryStore(false); + + final Blob b = new Blob(); + b.data = TEST_BLOB_DATA; + final String l2Key = "fakeKey"; + + // enqueue multiple ipms requests + mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, + status -> { + assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); + }); + mStore.retrieveNetworkAttributes(l2Key, + (status, key, attr) -> { + assertTrue("Retrieve network attributes not successful : " + + status.resultCode, status.isSuccess()); + assertEquals(l2Key, key); + assertEquals(TEST_NETWORK_ATTRIBUTES, attr); + }); + mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b, + status -> { + assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); + }); + mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME, + (status, key, name, data) -> { + assertTrue("Retrieve blob status not successful : " + status.resultCode, + status.isSuccess()); + assertEquals(l2Key, key); + assertEquals(name, TEST_DATA_NAME); + assertTrue(Arrays.equals(b.data, data.data)); + }); + + // get ipms service ready + mCbCaptor.getValue().onIpMemoryStoreFetched(mMockService); + + InOrder inOrder = inOrder(mMockService); + + inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any()); + inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any()); + inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME), + eq(b), any()); + inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID), + eq(TEST_OTHER_DATA_NAME), any()); + assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); + } + + @Test + public void testEnqueuedIpMsRequestsWithException() throws Exception { + startIpMemoryStore(true); + doThrow(RemoteException.class).when(mMockService).retrieveNetworkAttributes(any(), any()); + + final Blob b = new Blob(); + b.data = TEST_BLOB_DATA; + final String l2Key = "fakeKey"; + + // enqueue multiple ipms requests + mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, + status -> { + assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); + }); + mStore.retrieveNetworkAttributes(l2Key, + (status, key, attr) -> { + assertTrue("Retrieve network attributes not successful : " + + status.resultCode, status.isSuccess()); + assertEquals(l2Key, key); + assertEquals(TEST_NETWORK_ATTRIBUTES, attr); + }); + mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b, + status -> { + assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); + }); + mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME, + (status, key, name, data) -> { + assertTrue("Retrieve blob status not successful : " + status.resultCode, + status.isSuccess()); + assertEquals(l2Key, key); + assertEquals(name, TEST_DATA_NAME); + assertTrue(Arrays.equals(b.data, data.data)); + }); + + // verify the rest of the queue is still processed in order even if the remote exception + // occurs when calling one or more requests + InOrder inOrder = inOrder(mMockService); + + inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any()); + inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME), + eq(b), any()); + inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID), + eq(TEST_OTHER_DATA_NAME), any()); + assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); + } + + @Test + public void testEnqueuedIpMsRequestsCallbackFunctionWithException() throws Exception { + startIpMemoryStore(true); + + final Blob b = new Blob(); + b.data = TEST_BLOB_DATA; + final String l2Key = "fakeKey"; + + // enqueue multiple ipms requests + mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, + status -> { + assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); + }); + mStore.retrieveNetworkAttributes(l2Key, + (status, key, attr) -> { + throw new RuntimeException("retrieveNetworkAttributes test"); + }); + mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b, + status -> { + throw new RuntimeException("storeBlob test"); + }); + mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME, + (status, key, name, data) -> { + assertTrue("Retrieve blob status not successful : " + status.resultCode, + status.isSuccess()); + assertEquals(l2Key, key); + assertEquals(name, TEST_DATA_NAME); + assertTrue(Arrays.equals(b.data, data.data)); + }); + + // verify the rest of the queue is still processed in order even if when one or more + // callback throw the remote exception + InOrder inOrder = inOrder(mMockService); + + inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), + any()); + inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME), + eq(b), any()); + inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID), + eq(TEST_OTHER_DATA_NAME), any()); + assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); + } } 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 a83faf3477..fb84611cb6 100644 --- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java +++ b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity.ipmemorystore; +package com.android.server.net.ipmemorystore; import static org.junit.Assert.assertEquals; From 9ff61e4948187a78e2373c2aa634be1510203f7d Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 10 May 2019 04:33:43 -0700 Subject: [PATCH 073/130] Support strict mode private DNS on VPNs that provide Internet. Currently, strict mode private DNS does not work on VPNs because NetworkMonitor does not validate VPNs. When a VPN connects, it immediately transitions to ValidatedState, skipping private DNS hostname resolution. This change makes NetworkMonitor perform private DNS hostname resolution and evaluation even on VPNs. In order to ensure that the system always immediately switches to the VPN as soon as it connects, remove the unvalidated penalty for VPN networks. This ensures that the VPN score is always 101 and the VPN always outscores other networks as soon as it connects. Previously, it would only outscore other networks when no-op validation completed. Bug: 122652057 Test: atest FrameworksNetTests NetworkStackTests Test: manually ran a VPN with private DNS in strict mode atest android.net.cts.ConnectivityManagerTest com.android.cts.net.HostsideVpnTests Change-Id: Iaa78a7edcf23755c89d7b354edbc28d37d74d891 Merged-In: Iaa78a7edcf23755c89d7b354edbc28d37d74d891 (cherry picked from commit 414b8c8b1ce8ae2ad6ef95c1ffba19062077d3e6) --- .../android/server/ConnectivityService.java | 10 +-- .../server/connectivity/NetworkAgentInfo.java | 4 +- .../server/ConnectivityServiceTest.java | 61 ++++++++++++++++++- 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 55f9826eff..facc299450 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -40,7 +40,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.uidRulesToString; -import static android.net.shared.NetworkMonitorUtils.isValidationRequired; +import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired; import static android.os.Process.INVALID_UID; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; @@ -2826,8 +2826,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private boolean networkRequiresValidation(NetworkAgentInfo nai) { - return isValidationRequired(nai.networkCapabilities); + private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) { + return isPrivateDnsValidationRequired(nai.networkCapabilities); } private void handleFreshlyValidatedNetwork(NetworkAgentInfo nai) { @@ -2845,7 +2845,7 @@ public class ConnectivityService extends IConnectivityManager.Stub for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { handlePerNetworkPrivateDnsConfig(nai, cfg); - if (networkRequiresValidation(nai)) { + if (networkRequiresPrivateDnsValidation(nai)) { handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); } } @@ -2854,7 +2854,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handlePerNetworkPrivateDnsConfig(NetworkAgentInfo nai, PrivateDnsConfig cfg) { // Private DNS only ever applies to networks that might provide // Internet access and therefore also require validation. - if (!networkRequiresValidation(nai)) return; + if (!networkRequiresPrivateDnsValidation(nai)) return; // Notify the NetworkAgentInfo/NetworkMonitor in case NetworkMonitor needs to cancel or // schedule DNS resolutions. If a DNS resolution is required the diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index cfa91314f4..34772d062f 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -483,11 +483,11 @@ public class NetworkAgentInfo implements Comparable { // down an explicitly selected network before the user gets a chance to prefer it when // a higher-scoring network (e.g., Ethernet) is available. if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) { - return ConnectivityConstants.MAXIMUM_NETWORK_SCORE; + return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE; } int score = currentScore; - if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) { + if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) { score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY; } if (score < 0) score = 0; diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 0ef56e553a..fe1378736e 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -28,6 +28,7 @@ import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; import static android.net.ConnectivityManager.TYPE_NONE; +import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID; import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY; @@ -489,7 +490,7 @@ public class ConnectivityServiceTest { MockNetworkAgent(int transport, LinkProperties linkProperties) { final int type = transportToLegacyType(transport); - final String typeName = ConnectivityManager.getNetworkTypeName(transport); + final String typeName = ConnectivityManager.getNetworkTypeName(type); mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock"); mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(transport); @@ -619,6 +620,10 @@ public class ConnectivityServiceTest { mNetworkAgent.sendNetworkScore(mScore); } + public int getScore() { + return mScore; + } + public void explicitlySelected(boolean acceptUnvalidated) { mNetworkAgent.explicitlySelected(acceptUnvalidated); } @@ -1330,6 +1335,8 @@ public class ConnectivityServiceTest { return TYPE_WIFI; case TRANSPORT_CELLULAR: return TYPE_MOBILE; + case TRANSPORT_VPN: + return TYPE_VPN; default: return TYPE_NONE; } @@ -5367,6 +5374,58 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(defaultCallback); } + @Test + public void testVpnUnvalidated() throws Exception { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(callback); + + // Bring up Ethernet. + mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET); + mEthernetNetworkAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); + callback.assertNoCallback(); + + // Bring up a VPN that has the INTERNET capability, initially unvalidated. + final int uid = Process.myUid(); + final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.setUids(ranges); + vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */); + mMockVpn.connect(); + + // Even though the VPN is unvalidated, it becomes the default network for our app. + callback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); + // TODO: this looks like a spurious callback. + callback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent); + callback.assertNoCallback(); + + assertTrue(vpnNetworkAgent.getScore() > mEthernetNetworkAgent.getScore()); + assertEquals(ConnectivityConstants.VPN_DEFAULT_SCORE, vpnNetworkAgent.getScore()); + assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + + NetworkCapabilities nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork()); + assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED)); + assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET)); + + assertFalse(NetworkMonitorUtils.isValidationRequired(vpnNetworkAgent.mNetworkCapabilities)); + assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired( + vpnNetworkAgent.mNetworkCapabilities)); + + // Pretend that the VPN network validates. + vpnNetworkAgent.setNetworkValid(); + vpnNetworkAgent.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.assertNoCallback(); + + vpnNetworkAgent.disconnect(); + callback.expectCallback(CallbackState.LOST, vpnNetworkAgent); + callback.expectAvailableCallbacksValidated(mEthernetNetworkAgent); + } + @Test public void testVpnSetUnderlyingNetworks() { final int uid = Process.myUid(); From cd36ebcfcd3a413f1e58397452b84104d229dfa2 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Fri, 10 May 2019 15:28:40 -0700 Subject: [PATCH 074/130] Add LinkProperties common test cases Bug: 129198747 Test: atest FrameworksNetTests Test: atest CtsNetTestCases: added tests pass Change-Id: I03d162ea3c5bc2ccb8f913bbfdf85ebcd194c35a Merged-In: I8d36177cbf4f39da602331e091a60a40f6eaea33 Merged-In: I03d162ea3c5bc2ccb8f913bbfdf85ebcd194c35a (cherry picked from commit 385757291c2e822f1338157a2368e319d4048c89) --- .../java/android/net/LinkPropertiesTest.java | 269 +++++++++++++++--- 1 file changed, 225 insertions(+), 44 deletions(-) diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java index 709f5f69aa..e1c4238f12 100644 --- a/tests/net/common/java/android/net/LinkPropertiesTest.java +++ b/tests/net/common/java/android/net/LinkPropertiesTest.java @@ -18,6 +18,7 @@ package android.net; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -46,28 +47,80 @@ import java.util.Set; @RunWith(AndroidJUnit4.class) @SmallTest public class LinkPropertiesTest { - private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1"); - private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress( + private static final InetAddress ADDRV4 = InetAddresses.parseNumericAddress("75.208.6.1"); + private static final InetAddress ADDRV6 = InetAddresses.parseNumericAddress( "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); - private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1"); - private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1"); - private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888"); - private static InetAddress PCSCFV6 = NetworkUtils.numericToInetAddress( + private static final InetAddress DNS1 = InetAddresses.parseNumericAddress("75.208.7.1"); + private static final InetAddress DNS2 = InetAddresses.parseNumericAddress("69.78.7.1"); + private static final InetAddress DNS6 = InetAddresses.parseNumericAddress( + "2001:4860:4860::8888"); + private static final InetAddress PRIVDNS1 = InetAddresses.parseNumericAddress("1.1.1.1"); + private static final InetAddress PRIVDNS2 = InetAddresses.parseNumericAddress("1.0.0.1"); + private static final InetAddress PRIVDNS6 = InetAddresses.parseNumericAddress( + "2606:4700:4700::1111"); + private static final InetAddress PCSCFV4 = InetAddresses.parseNumericAddress("10.77.25.37"); + private static final InetAddress PCSCFV6 = InetAddresses.parseNumericAddress( "2001:0db8:85a3:0000:0000:8a2e:0370:1"); - private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1"); - private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1"); - private static InetAddress GATEWAY61 = NetworkUtils.numericToInetAddress("fe80::6:0000:613"); - private static InetAddress GATEWAY62 = NetworkUtils.numericToInetAddress("fe80::6:2222"); - private static String NAME = "qmi0"; - private static int MTU = 1500; - - private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32); - private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128); - private static LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64"); + private static final InetAddress GATEWAY1 = InetAddresses.parseNumericAddress("75.208.8.1"); + private static final InetAddress GATEWAY2 = InetAddresses.parseNumericAddress("69.78.8.1"); + private static final InetAddress GATEWAY61 = InetAddresses.parseNumericAddress( + "fe80::6:0000:613"); + private static final InetAddress GATEWAY62 = InetAddresses.parseNumericAddress("fe80::6:2222"); + private static final String NAME = "qmi0"; + private static final String DOMAINS = "google.com"; + private static final String PRIV_DNS_SERVER_NAME = "private.dns.com"; + private static final String TCP_BUFFER_SIZES = "524288,1048576,2097152,262144,524288,1048576"; + private static final int MTU = 1500; + private static final LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32); + private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128); + private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64"); // TODO: replace all calls to NetworkUtils.numericToInetAddress with calls to this method. private InetAddress Address(String addrString) { - return NetworkUtils.numericToInetAddress(addrString); + return InetAddresses.parseNumericAddress(addrString); + } + + private void checkEmpty(final LinkProperties lp) { + assertEquals(0, lp.getAllInterfaceNames().size()); + assertEquals(0, lp.getAllAddresses().size()); + assertEquals(0, lp.getDnsServers().size()); + assertEquals(0, lp.getValidatedPrivateDnsServers().size()); + assertEquals(0, lp.getPcscfServers().size()); + assertEquals(0, lp.getAllRoutes().size()); + assertEquals(0, lp.getAllLinkAddresses().size()); + assertEquals(0, lp.getStackedLinks().size()); + assertEquals(0, lp.getMtu()); + assertNull(lp.getPrivateDnsServerName()); + assertNull(lp.getDomains()); + assertNull(lp.getHttpProxy()); + assertNull(lp.getTcpBufferSizes()); + assertNull(lp.getNat64Prefix()); + assertFalse(lp.isProvisioned()); + assertFalse(lp.isIpv4Provisioned()); + assertFalse(lp.isIpv6Provisioned()); + assertFalse(lp.isPrivateDnsActive()); + } + + private LinkProperties makeTestObject() { + final LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(NAME); + lp.addLinkAddress(LINKADDRV4); + lp.addLinkAddress(LINKADDRV6); + lp.addDnsServer(DNS1); + lp.addDnsServer(DNS2); + lp.addValidatedPrivateDnsServer(PRIVDNS1); + lp.addValidatedPrivateDnsServer(PRIVDNS2); + lp.setUsePrivateDns(true); + lp.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME); + lp.addPcscfServer(PCSCFV6); + lp.setDomains(DOMAINS); + lp.addRoute(new RouteInfo(GATEWAY1)); + lp.addRoute(new RouteInfo(GATEWAY2)); + lp.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888)); + lp.setMtu(MTU); + lp.setTcpBufferSizes(TCP_BUFFER_SIZES); + lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96")); + return lp; } public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) { @@ -170,8 +223,7 @@ public class LinkPropertiesTest { target.clear(); target.setInterfaceName(NAME); // change link addresses - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress("75.208.6.2"), 32)); + target.addLinkAddress(new LinkAddress(Address("75.208.6.2"), 32)); target.addLinkAddress(LINKADDRV6); target.addDnsServer(DNS1); target.addDnsServer(DNS2); @@ -186,7 +238,7 @@ public class LinkPropertiesTest { target.addLinkAddress(LINKADDRV4); target.addLinkAddress(LINKADDRV6); // change dnses - target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2")); + target.addDnsServer(Address("75.208.7.2")); target.addDnsServer(DNS2); target.addPcscfServer(PCSCFV6); target.addRoute(new RouteInfo(GATEWAY1)); @@ -198,11 +250,10 @@ public class LinkPropertiesTest { target.setInterfaceName(NAME); target.addLinkAddress(LINKADDRV4); target.addLinkAddress(LINKADDRV6); - target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2")); + target.addDnsServer(Address("75.208.7.2")); target.addDnsServer(DNS2); // change pcscf - target.addPcscfServer(NetworkUtils.numericToInetAddress( - "2001::1")); + target.addPcscfServer(Address("2001::1")); target.addRoute(new RouteInfo(GATEWAY1)); target.addRoute(new RouteInfo(GATEWAY2)); target.setMtu(MTU); @@ -215,7 +266,7 @@ public class LinkPropertiesTest { target.addDnsServer(DNS1); target.addDnsServer(DNS2); // change gateway - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2"))); + target.addRoute(new RouteInfo(Address("75.208.8.2"))); target.addRoute(new RouteInfo(GATEWAY2)); target.setMtu(MTU); assertFalse(source.equals(target)); @@ -285,10 +336,15 @@ public class LinkPropertiesTest { } } + private void assertAllRoutesNotHaveInterface(String iface, LinkProperties lp) { + for (RouteInfo r : lp.getRoutes()) { + assertNotEquals(iface, r.getInterface()); + } + } + @Test public void testRouteInterfaces() { - LinkAddress prefix = new LinkAddress( - NetworkUtils.numericToInetAddress("2001:db8::"), 32); + LinkAddress prefix = new LinkAddress(Address("2001:db8::"), 32); InetAddress address = ADDRV6; // Add a route with no interface to a LinkProperties with no interface. No errors. @@ -312,6 +368,8 @@ public class LinkPropertiesTest { // Change the interface name. All the routes should change their interface name too. lp.setInterfaceName("rmnet0"); assertAllRoutesHaveInterface("rmnet0", lp); + assertAllRoutesNotHaveInterface(null, lp); + assertAllRoutesNotHaveInterface("wlan0", lp); // Now add a route with the wrong interface. This causes an exception too. try { @@ -325,6 +383,7 @@ public class LinkPropertiesTest { lp.addRoute(r); assertEquals(2, lp.getRoutes().size()); assertAllRoutesHaveInterface("wlan0", lp); + assertAllRoutesNotHaveInterface("rmnet0", lp); // Routes with null interfaces are converted to wlan0. r = RouteInfo.makeHostRoute(ADDRV6, null); @@ -334,14 +393,23 @@ public class LinkPropertiesTest { // Check comparisons work. LinkProperties lp2 = new LinkProperties(lp); - assertAllRoutesHaveInterface("wlan0", lp); + assertAllRoutesHaveInterface("wlan0", lp2); assertEquals(0, lp.compareAllRoutes(lp2).added.size()); assertEquals(0, lp.compareAllRoutes(lp2).removed.size()); lp2.setInterfaceName("p2p0"); assertAllRoutesHaveInterface("p2p0", lp2); + assertAllRoutesNotHaveInterface("wlan0", lp2); assertEquals(3, lp.compareAllRoutes(lp2).added.size()); assertEquals(3, lp.compareAllRoutes(lp2).removed.size()); + + // Check remove works + lp.removeRoute(new RouteInfo(prefix, address, null)); + assertEquals(3, lp.getRoutes().size()); + lp.removeRoute(new RouteInfo(prefix, address, "wlan0")); + assertEquals(2, lp.getRoutes().size()); + assertAllRoutesHaveInterface("wlan0", lp); + assertAllRoutesNotHaveInterface("p2p0", lp); } @Test @@ -488,18 +556,26 @@ public class LinkPropertiesTest { } @Test - public void testSetLinkAddresses() { - LinkProperties lp = new LinkProperties(); + public void testLinkAddresses() { + final LinkProperties lp = new LinkProperties(); lp.addLinkAddress(LINKADDRV4); lp.addLinkAddress(LINKADDRV6); - LinkProperties lp2 = new LinkProperties(); + final LinkProperties lp2 = new LinkProperties(); lp2.addLinkAddress(LINKADDRV6); - assertFalse(lp.equals(lp2)); + final LinkProperties lp3 = new LinkProperties(); + final List linkAddresses = Arrays.asList(LINKADDRV4); + lp3.setLinkAddresses(linkAddresses); - lp2.setLinkAddresses(lp.getLinkAddresses()); - assertTrue(lp.equals(lp)); + assertFalse(lp.equals(lp2)); + assertFalse(lp2.equals(lp3)); + + lp.removeLinkAddress(LINKADDRV4); + assertTrue(lp.equals(lp2)); + + lp2.setLinkAddresses(lp3.getLinkAddresses()); + assertTrue(lp2.equals(lp3)); } @Test @@ -675,9 +751,9 @@ public class LinkPropertiesTest { assertTrue(v4lp.isReachable(DNS2)); final LinkProperties v6lp = new LinkProperties(); - final InetAddress kLinkLocalDns = NetworkUtils.numericToInetAddress("fe80::6:1"); - final InetAddress kLinkLocalDnsWithScope = NetworkUtils.numericToInetAddress("fe80::6:2%43"); - final InetAddress kOnLinkDns = NetworkUtils.numericToInetAddress("2001:db8:85a3::53"); + final InetAddress kLinkLocalDns = Address("fe80::6:1"); + final InetAddress kLinkLocalDnsWithScope = Address("fe80::6:2%43"); + final InetAddress kOnLinkDns = Address("2001:db8:85a3::53"); assertFalse(v6lp.isReachable(kLinkLocalDns)); assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope)); assertFalse(v6lp.isReachable(kOnLinkDns)); @@ -686,8 +762,7 @@ public class LinkPropertiesTest { // Add a link-local route, making the link-local DNS servers reachable. Because // we assume the presence of an IPv6 link-local address, link-local DNS servers // are considered reachable, but only those with a non-zero scope identifier. - assertTrue(v6lp.addRoute(new RouteInfo( - new IpPrefix(NetworkUtils.numericToInetAddress("fe80::"), 64)))); + assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(Address("fe80::"), 64)))); assertFalse(v6lp.isReachable(kLinkLocalDns)); assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope)); assertFalse(v6lp.isReachable(kOnLinkDns)); @@ -703,8 +778,7 @@ public class LinkPropertiesTest { // Add a global route on link, but no global address yet. DNS servers reachable // via a route that doesn't require a gateway: give them the benefit of the // doubt and hope the link-local source address suffices for communication. - assertTrue(v6lp.addRoute(new RouteInfo( - new IpPrefix(NetworkUtils.numericToInetAddress("2001:db8:85a3::"), 64)))); + assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(Address("2001:db8:85a3::"), 64)))); assertFalse(v6lp.isReachable(kLinkLocalDns)); assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope)); assertTrue(v6lp.isReachable(kOnLinkDns)); @@ -766,8 +840,8 @@ public class LinkPropertiesTest { LinkProperties rmnet1 = new LinkProperties(); rmnet1.setInterfaceName("rmnet1"); rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8")); - RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null, - NetworkUtils.numericToInetAddress("10.0.0.1"), rmnet1.getInterfaceName()); + RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null, Address("10.0.0.1"), + rmnet1.getInterfaceName()); RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null, rmnet1.getInterfaceName()); rmnet1.addRoute(defaultRoute1); @@ -785,8 +859,8 @@ public class LinkPropertiesTest { rmnet2.setInterfaceName("rmnet2"); rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64")); rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64")); - RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null, - NetworkUtils.numericToInetAddress("2001:db8::1"), rmnet2.getInterfaceName()); + RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null, Address("2001:db8::1"), + rmnet2.getInterfaceName()); RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null, rmnet2.getInterfaceName()); RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null, @@ -876,4 +950,111 @@ public class LinkPropertiesTest { LinkProperties empty = new LinkProperties(); TestUtils.assertParcelingIsLossless(empty); } + + @Test + public void testConstructor() { + LinkProperties lp = new LinkProperties(); + checkEmpty(lp); + assertLinkPropertiesEqual(lp, new LinkProperties(lp)); + assertLinkPropertiesEqual(lp, new LinkProperties()); + + lp = makeTestObject(); + assertLinkPropertiesEqual(lp, new LinkProperties(lp)); + } + + @Test + public void testDnsServers() { + final LinkProperties lp = new LinkProperties(); + final List dnsServers = Arrays.asList(DNS1, DNS2); + lp.setDnsServers(dnsServers); + assertEquals(2, lp.getDnsServers().size()); + assertEquals(DNS1, lp.getDnsServers().get(0)); + assertEquals(DNS2, lp.getDnsServers().get(1)); + + lp.removeDnsServer(DNS1); + assertEquals(1, lp.getDnsServers().size()); + assertEquals(DNS2, lp.getDnsServers().get(0)); + + lp.addDnsServer(DNS6); + assertEquals(2, lp.getDnsServers().size()); + assertEquals(DNS2, lp.getDnsServers().get(0)); + assertEquals(DNS6, lp.getDnsServers().get(1)); + } + + @Test + public void testValidatedPrivateDnsServers() { + final LinkProperties lp = new LinkProperties(); + final List privDnsServers = Arrays.asList(PRIVDNS1, PRIVDNS2); + lp.setValidatedPrivateDnsServers(privDnsServers); + assertEquals(2, lp.getValidatedPrivateDnsServers().size()); + assertEquals(PRIVDNS1, lp.getValidatedPrivateDnsServers().get(0)); + assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(1)); + + lp.removeValidatedPrivateDnsServer(PRIVDNS1); + assertEquals(1, lp.getValidatedPrivateDnsServers().size()); + assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0)); + + lp.addValidatedPrivateDnsServer(PRIVDNS6); + assertEquals(2, lp.getValidatedPrivateDnsServers().size()); + assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0)); + assertEquals(PRIVDNS6, lp.getValidatedPrivateDnsServers().get(1)); + } + + @Test + public void testPcscfServers() { + final LinkProperties lp = new LinkProperties(); + final List pcscfServers = Arrays.asList(PCSCFV4); + lp.setPcscfServers(pcscfServers); + assertEquals(1, lp.getPcscfServers().size()); + assertEquals(PCSCFV4, lp.getPcscfServers().get(0)); + + lp.removePcscfServer(PCSCFV4); + assertEquals(0, lp.getPcscfServers().size()); + + lp.addPcscfServer(PCSCFV6); + assertEquals(1, lp.getPcscfServers().size()); + assertEquals(PCSCFV6, lp.getPcscfServers().get(0)); + } + + @Test + public void testTcpBufferSizes() { + final LinkProperties lp = makeTestObject(); + assertEquals(TCP_BUFFER_SIZES, lp.getTcpBufferSizes()); + + lp.setTcpBufferSizes(null); + assertNull(lp.getTcpBufferSizes()); + } + + @Test + public void testHasIpv6DefaultRoute() { + final LinkProperties lp = makeTestObject(); + assertFalse(lp.hasIPv6DefaultRoute()); + + lp.addRoute(new RouteInfo(GATEWAY61)); + assertTrue(lp.hasIPv6DefaultRoute()); + } + + @Test + public void testHttpProxy() { + final LinkProperties lp = makeTestObject(); + assertTrue(lp.getHttpProxy().equals(ProxyInfo.buildDirectProxy("test", 8888))); + } + + @Test + public void testPrivateDnsServerName() { + final LinkProperties lp = makeTestObject(); + assertEquals(PRIV_DNS_SERVER_NAME, lp.getPrivateDnsServerName()); + + lp.setPrivateDnsServerName(null); + assertNull(lp.getPrivateDnsServerName()); + } + + @Test + public void testUsePrivateDns() { + final LinkProperties lp = makeTestObject(); + assertTrue(lp.isPrivateDnsActive()); + + lp.clear(); + assertFalse(lp.isPrivateDnsActive()); + } } From 9a5d592793d4867d2ff7508061c82465336090b0 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Sun, 12 May 2019 10:37:59 -0700 Subject: [PATCH 075/130] Add ApfCapabilities common test cases Bug: 129199900 Test: atest FrameworksNetTests Test: atest CtsNetTestCases: added tests pass Change-Id: I737ab11ccd1bf6f92bae4eae21e67d4d6f86a758 Merged-In: Icfd80943212430b2a0e6a4b55f53270cbc3d1693 Merged-In: I737ab11ccd1bf6f92bae4eae21e67d4d6f86a758 (cherry picked from commit ce54fa5cb392c38bfec62b81664fcc25098eb9dc) --- .../android/net/apf/ApfCapabilitiesTest.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java index 3ed8a86b2f..0ce7c91c04 100644 --- a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java +++ b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java @@ -17,7 +17,9 @@ package android.net.apf; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -32,8 +34,12 @@ import org.junit.runner.RunWith; @SmallTest public class ApfCapabilitiesTest { @Test - public void testParcelUnparcel() { + public void testConstructAndParcel() { final ApfCapabilities caps = new ApfCapabilities(123, 456, 789); + assertEquals(123, caps.apfVersionSupported); + assertEquals(456, caps.maximumApfProgramSize); + assertEquals(789, caps.apfPacketFormat); + ParcelableTestUtil.assertFieldCountEquals(3, ApfCapabilities.class); TestUtils.assertParcelingIsLossless(caps); @@ -46,4 +52,14 @@ public class ApfCapabilitiesTest { assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3)); assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3)); } + + @Test + public void testHasDataAccess() { + //hasDataAccess is only supported starting at apf version 4. + ApfCapabilities caps = new ApfCapabilities(1 /* apfVersionSupported */, 2, 3); + assertFalse(caps.hasDataAccess()); + + caps = new ApfCapabilities(4 /* apfVersionSupported */, 5, 6); + assertTrue(caps.hasDataAccess()); + } } From ec4eb8f4486c5385210df1b2d8d44c6b90f21bde Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 17 Apr 2019 15:22:46 +0800 Subject: [PATCH 076/130] Support customization of supported keepalive count per transport This change specifies the required minimum supported keepalives in SDK, and allows OEMs to customize supported keepalive count per network through resource overlay. Bug: 129371366 Test: 1. m -j doc-comment-check-docs 2. atest FrameworksNetTests Clean cherry-pick of aosp/946359 Change-Id: I06840834d0ee8121358bf4829fe47ecf9964d395 Merged-In: I0218f3674628c13ead63fc9a873895ba7f113033 Merged-In: Ia667386c1a8949839871a6949d79552d9c8b88f0 --- core/java/android/net/SocketKeepalive.java | 4 + .../java/android/net/util/KeepaliveUtils.java | 121 ++++++++++++++++ .../server/connectivity/KeepaliveTracker.java | 58 ++++++-- .../android/net/util/KeepaliveUtilsTest.kt | 130 ++++++++++++++++++ 4 files changed, 300 insertions(+), 13 deletions(-) create mode 100644 core/java/android/net/util/KeepaliveUtils.java create mode 100644 tests/net/java/android/net/util/KeepaliveUtilsTest.kt diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java index 9d91620bdf..46eddde968 100644 --- a/core/java/android/net/SocketKeepalive.java +++ b/core/java/android/net/SocketKeepalive.java @@ -43,6 +43,10 @@ import java.util.concurrent.Executor; * To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call * {@link SocketKeepalive.Callback#onStopped} if the operation was successful or * {@link SocketKeepalive.Callback#onError} if an error occurred. + * + * The device SHOULD support keepalive offload. If it does not, it MUST reply with + * {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload + * request. If it does, it MUST support at least 3 concurrent keepalive slots per transport. */ public abstract class SocketKeepalive implements AutoCloseable { static final String TAG = "SocketKeepalive"; diff --git a/core/java/android/net/util/KeepaliveUtils.java b/core/java/android/net/util/KeepaliveUtils.java new file mode 100644 index 0000000000..569fed1fc9 --- /dev/null +++ b/core/java/android/net/util/KeepaliveUtils.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2019 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.util; + +import android.annotation.NonNull; +import android.content.Context; +import android.content.res.Resources; +import android.net.NetworkCapabilities; +import android.text.TextUtils; +import android.util.AndroidRuntimeException; + +import com.android.internal.R; + +/** + * Collection of utilities for socket keepalive offload. + * + * @hide + */ +public final class KeepaliveUtils { + + public static final String TAG = "KeepaliveUtils"; + + // Minimum supported keepalive count per transport if the network supports keepalive. + public static final int MIN_SUPPORTED_KEEPALIVE_COUNT = 3; + + public static class KeepaliveDeviceConfigurationException extends AndroidRuntimeException { + public KeepaliveDeviceConfigurationException(final String msg) { + super(msg); + } + } + + /** + * Read supported keepalive count for each transport type from overlay resource. This should be + * used to create a local variable store of resource customization, and use it as the input for + * {@link getSupportedKeepalivesForNetworkCapabilities}. + * + * @param context The context to read resource from. + * @return An array of supported keepalive count for each transport type. + */ + @NonNull + public static int[] getSupportedKeepalives(@NonNull Context context) { + String[] res = null; + try { + res = context.getResources().getStringArray( + R.array.config_networkSupportedKeepaliveCount); + } catch (Resources.NotFoundException unused) { + } + if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource"); + + final int[] ret = new int[NetworkCapabilities.MAX_TRANSPORT + 1]; + for (final String row : res) { + if (TextUtils.isEmpty(row)) { + throw new KeepaliveDeviceConfigurationException("Empty string"); + } + final String[] arr = row.split(","); + if (arr.length != 2) { + throw new KeepaliveDeviceConfigurationException("Invalid parameter length"); + } + + int transport; + int supported; + try { + transport = Integer.parseInt(arr[0]); + supported = Integer.parseInt(arr[1]); + } catch (NumberFormatException e) { + throw new KeepaliveDeviceConfigurationException("Invalid number format"); + } + + if (!NetworkCapabilities.isValidTransport(transport)) { + throw new KeepaliveDeviceConfigurationException("Invalid transport " + transport); + } + + // Customized values should be either 0 to indicate the network doesn't support + // keepalive offload, or a positive value that is at least + // MIN_SUPPORTED_KEEPALIVE_COUNT if supported. + if (supported != 0 && supported < MIN_SUPPORTED_KEEPALIVE_COUNT) { + throw new KeepaliveDeviceConfigurationException( + "Invalid supported count " + supported + " for " + + NetworkCapabilities.transportNameOf(transport)); + } + ret[transport] = supported; + } + return ret; + } + + /** + * Get supported keepalive count for the given {@link NetworkCapabilities}. + * + * @param supportedKeepalives An array of supported keepalive count for each transport type. + * @param nc The {@link NetworkCapabilities} of the network the socket keepalive is on. + * + * @return Supported keepalive count for the given {@link NetworkCapabilities}. + */ + public static int getSupportedKeepalivesForNetworkCapabilities( + @NonNull int[] supportedKeepalives, @NonNull NetworkCapabilities nc) { + final int[] transports = nc.getTransportTypes(); + if (transports.length == 0) return 0; + int supportedCount = supportedKeepalives[transports[0]]; + // Iterate through transports and return minimum supported value. + for (final int transport : transports) { + if (supportedCount > supportedKeepalives[transport]) { + supportedCount = supportedKeepalives[transport]; + } + } + return supportedCount; + } +} diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 35f7ea3ae0..1e3e6a5b5a 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -29,6 +29,7 @@ import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL; import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK; import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET; +import static android.net.SocketKeepalive.ERROR_UNSUPPORTED; import static android.net.SocketKeepalive.MAX_INTERVAL_SEC; import static android.net.SocketKeepalive.MIN_INTERVAL_SEC; import static android.net.SocketKeepalive.NO_KEEPALIVE; @@ -46,6 +47,7 @@ import android.net.SocketKeepalive.InvalidPacketException; 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; import android.os.IBinder; @@ -57,6 +59,7 @@ import android.system.Os; import android.util.Log; import android.util.Pair; +import com.android.internal.R; import com.android.internal.util.HexDump; import com.android.internal.util.IndentingPrintWriter; @@ -65,6 +68,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; /** @@ -90,10 +94,23 @@ public class KeepaliveTracker { @NonNull private final Context mContext; + // Supported keepalive count for each transport type, can be configured through + // config_networkSupportedKeepaliveCount. For better error handling, use + // {@link getSupportedKeepalivesForNetworkCapabilities} instead of direct access. + @NonNull + private final int[] mSupportedKeepalives; + + // Reserved privileged keepalive slots per transport. Caller's permission will be enforced if + // the number of remaining keepalive slots is less than or equal to the threshold. + private final int mReservedPrivilegedSlots; + public KeepaliveTracker(Context context, Handler handler) { mConnectivityServiceHandler = handler; mTcpController = new TcpKeepaliveController(handler); mContext = context; + mSupportedKeepalives = KeepaliveUtils.getSupportedKeepalives(mContext); + mReservedPrivilegedSlots = mContext.getResources().getInteger( + R.integer.config_reservedPrivilegedKeepaliveSlots); } /** @@ -115,11 +132,6 @@ public class KeepaliveTracker { public static final int TYPE_NATT = 1; public static final int TYPE_TCP = 2; - // Max allowed unprivileged keepalive slots per network. Caller's permission will be - // enforced if number of existing keepalives reach this limit. - // TODO: consider making this limit configurable via resources. - private static final int MAX_UNPRIVILEGED_SLOTS = 3; - // Keepalive slot. A small integer that identifies this keepalive among the ones handled // by this network. private int mSlot = NO_KEEPALIVE; @@ -246,24 +258,42 @@ public class KeepaliveTracker { private int checkPermission() { final HashMap networkKeepalives = mKeepalives.get(mNai); - int unprivilegedCount = 0; if (networkKeepalives == null) { return ERROR_INVALID_NETWORK; } - for (KeepaliveInfo ki : networkKeepalives.values()) { - if (!ki.mPrivileged) { - unprivilegedCount++; - } - if (unprivilegedCount >= MAX_UNPRIVILEGED_SLOTS) { - return mPrivileged ? SUCCESS : ERROR_INSUFFICIENT_RESOURCES; - } + + if (mPrivileged) return SUCCESS; + + final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( + mSupportedKeepalives, mNai.networkCapabilities); + + int takenUnprivilegedSlots = 0; + for (final KeepaliveInfo ki : networkKeepalives.values()) { + if (!ki.mPrivileged) ++takenUnprivilegedSlots; } + if (takenUnprivilegedSlots > supported - mReservedPrivilegedSlots) { + return ERROR_INSUFFICIENT_RESOURCES; + } + + return SUCCESS; + } + + private int checkLimit() { + final HashMap networkKeepalives = mKeepalives.get(mNai); + if (networkKeepalives == null) { + return ERROR_INVALID_NETWORK; + } + final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( + mSupportedKeepalives, mNai.networkCapabilities); + if (supported == 0) return ERROR_UNSUPPORTED; + if (networkKeepalives.size() > supported) return ERROR_INSUFFICIENT_RESOURCES; return SUCCESS; } private int isValid() { synchronized (mNai) { int error = checkInterval(); + if (error == SUCCESS) error = checkLimit(); if (error == SUCCESS) error = checkPermission(); if (error == SUCCESS) error = checkNetworkConnected(); if (error == SUCCESS) error = checkSourceAddress(); @@ -642,6 +672,8 @@ public class KeepaliveTracker { } public void dump(IndentingPrintWriter pw) { + pw.println("Supported Socket keepalives: " + Arrays.toString(mSupportedKeepalives)); + pw.println("Reserved Privileged keepalives: " + mReservedPrivilegedSlots); pw.println("Socket keepalives:"); pw.increaseIndent(); for (NetworkAgentInfo nai : mKeepalives.keySet()) { diff --git a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt new file mode 100644 index 0000000000..814e06e311 --- /dev/null +++ b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2019 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.util + +import android.content.Context +import android.content.res.Resources +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.MAX_TRANSPORT +import android.net.NetworkCapabilities.TRANSPORT_CELLULAR +import android.net.NetworkCapabilities.TRANSPORT_ETHERNET +import android.net.NetworkCapabilities.TRANSPORT_VPN +import android.net.NetworkCapabilities.TRANSPORT_WIFI +import androidx.test.filters.SmallTest +import com.android.internal.R +import org.junit.Assert.assertArrayEquals +import org.junit.Assert.assertEquals +import org.junit.Assert.fail +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.ArgumentMatchers +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock + +/** + * Tests for [KeepaliveUtils]. + * + * Build, install and run with: + * atest android.net.util.KeepaliveUtilsTest + */ +@RunWith(JUnit4::class) +@SmallTest +class KeepaliveUtilsTest { + + // Prepare mocked context with given resource strings. + private fun getMockedContextWithStringArrayRes(id: Int, res: Array?): Context { + val mockRes = mock(Resources::class.java) + doReturn(res).`when`(mockRes).getStringArray(ArgumentMatchers.eq(id)) + + return mock(Context::class.java).apply { + doReturn(mockRes).`when`(this).getResources() + } + } + + @Test + fun testGetSupportedKeepalives() { + fun assertRunWithException(res: Array?) { + try { + val mockContext = getMockedContextWithStringArrayRes( + R.array.config_networkSupportedKeepaliveCount, res) + KeepaliveUtils.getSupportedKeepalives(mockContext) + fail("Expected KeepaliveDeviceConfigurationException") + } catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) { + } + } + + // Check resource with various invalid format. + assertRunWithException(null) + assertRunWithException(arrayOf(null)) + assertRunWithException(arrayOfNulls(10)) + assertRunWithException(arrayOf("")) + assertRunWithException(arrayOf("3,ABC")) + assertRunWithException(arrayOf("6,3,3")) + assertRunWithException(arrayOf("5")) + + // Check resource with invalid slots value. + assertRunWithException(arrayOf("2,2")) + assertRunWithException(arrayOf("3,-1")) + + // Check resource with invalid transport type. + assertRunWithException(arrayOf("-1,3")) + assertRunWithException(arrayOf("10,3")) + + // Check valid customization generates expected array. + val validRes = arrayOf("0,3", "1,0", "4,4") + val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0) + + val mockContext = getMockedContextWithStringArrayRes( + R.array.config_networkSupportedKeepaliveCount, validRes) + val actual = KeepaliveUtils.getSupportedKeepalives(mockContext) + assertArrayEquals(expectedValidRes, actual) + } + + @Test + fun testGetSupportedKeepalivesForNetworkCapabilities() { + // Mock customized supported keepalives for each transport type, and assuming: + // 3 for cellular, + // 6 for wifi, + // 0 for others. + val cust = IntArray(MAX_TRANSPORT + 1).apply { + this[TRANSPORT_CELLULAR] = 3 + this[TRANSPORT_WIFI] = 6 + } + + val nc = NetworkCapabilities() + // Check supported keepalives with single transport type. + nc.transportTypes = intArrayOf(TRANSPORT_CELLULAR) + assertEquals(3, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc)) + + // Check supported keepalives with multiple transport types. + nc.transportTypes = intArrayOf(TRANSPORT_WIFI, TRANSPORT_VPN) + assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc)) + + // Check supported keepalives with non-customized transport type. + nc.transportTypes = intArrayOf(TRANSPORT_ETHERNET) + assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc)) + + // Check supported keepalives with undefined transport type. + nc.transportTypes = intArrayOf(MAX_TRANSPORT + 1) + try { + KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc) + fail("Expected ArrayIndexOutOfBoundsException") + } catch (expected: ArrayIndexOutOfBoundsException) { + } + } +} From c602b402379616852deeff457376f5cb551cf0dc Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 30 Apr 2019 14:42:05 +0800 Subject: [PATCH 077/130] Limit unprivileged keepalives per uid Public APIs for creating unprivileged NATT socket keepalive might allow users to exhaust resource if malicious apps try to create keepalives with fd which is not created by IpSecService through binder call. Thus, this change add customizable limitation per uid to prevent resource exhaustion attack. Bug: 129371366 Bug: 132307230 Test: atest FrameworksNetTests Clean cherry-pick of aosp/954040 Merged-In: Ibcb91105e46f7e898b8aa7c2babc3344ef2c6257 Merged-In: Ia667386c1a8949839871a6949d79552d9c8b88f0 Change-Id: I92f6d977b6dfde4e1bf74df6b60c9a0b9e8eec40 --- .../server/connectivity/KeepaliveTracker.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 1e3e6a5b5a..44379264e5 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -104,6 +104,10 @@ public class KeepaliveTracker { // the number of remaining keepalive slots is less than or equal to the threshold. private final int mReservedPrivilegedSlots; + // Allowed unprivileged keepalive slots per uid. Caller's permission will be enforced if + // the number of remaining keepalive slots is less than or equal to the threshold. + private final int mAllowedUnprivilegedSlotsForUid; + public KeepaliveTracker(Context context, Handler handler) { mConnectivityServiceHandler = handler; mTcpController = new TcpKeepaliveController(handler); @@ -111,6 +115,8 @@ public class KeepaliveTracker { mSupportedKeepalives = KeepaliveUtils.getSupportedKeepalives(mContext); mReservedPrivilegedSlots = mContext.getResources().getInteger( R.integer.config_reservedPrivilegedKeepaliveSlots); + mAllowedUnprivilegedSlotsForUid = mContext.getResources().getInteger( + R.integer.config_allowedUnprivilegedKeepalivePerUid); } /** @@ -275,6 +281,18 @@ public class KeepaliveTracker { return ERROR_INSUFFICIENT_RESOURCES; } + // Count unprivileged keepalives for the same uid across networks. + int unprivilegedCountSameUid = 0; + for (final HashMap kaForNetwork : mKeepalives.values()) { + for (final KeepaliveInfo ki : kaForNetwork.values()) { + if (ki.mUid == mUid) { + unprivilegedCountSameUid++; + } + } + } + if (unprivilegedCountSameUid > mAllowedUnprivilegedSlotsForUid) { + return ERROR_INSUFFICIENT_RESOURCES; + } return SUCCESS; } @@ -674,6 +692,7 @@ public class KeepaliveTracker { public void dump(IndentingPrintWriter pw) { pw.println("Supported Socket keepalives: " + Arrays.toString(mSupportedKeepalives)); pw.println("Reserved Privileged keepalives: " + mReservedPrivilegedSlots); + pw.println("Allowed Unprivileged keepalives per uid: " + mAllowedUnprivilegedSlotsForUid); pw.println("Socket keepalives:"); pw.increaseIndent(); for (NetworkAgentInfo nai : mKeepalives.keySet()) { From 5e135ee2b956c7180e6641395a17969a1a6b0c25 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 15 Apr 2019 23:00:02 -0700 Subject: [PATCH 078/130] Release keepalive slot after stopped Currntly, keepalive slot is released when stop() is called. Next starting keepalive can use the same slot number while previous keepalive is still stopping. When the previous keepalive is stopped, the incoming as will be processed by the new keepalive. This change release keepalive slot after the result of stopping has returned. Thus, newly created keepalive cannot allocate the same slot number while lower layer is still processing stop event. This change also disable flaky assertions that are caused by test port has been occupied by other process. Bug: 129512753 Test: 1. atest com.android.server.ConnectivityServiceTest \ #testNattSocketKeepalives --generate-new-metrics 100 2. atest FrameworksNetTests --generate-new-metrics 10 3. simulate the fail case manually. Change-Id: I790f6bbc5efc3f088034ac45ec379da5f781d0ca Merged-In: I1991627545519ee5cb408a3df3a006f710f4af7b (cherry picked from commit 3523a3d02a1f88a3990ab9cc4948c705ecc713c8) --- .../server/connectivity/KeepaliveTracker.java | 59 ++++++++++++++----- .../server/ConnectivityServiceTest.java | 8 ++- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 44379264e5..ae58e994a5 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -209,6 +209,7 @@ public class KeepaliveTracker { case NOT_STARTED : return "NOT_STARTED"; case STARTING : return "STARTING"; case STARTED : return "STARTED"; + case STOPPING : return "STOPPING"; } throw new IllegalArgumentException("Unknown state"); } @@ -362,18 +363,27 @@ public class KeepaliveTracker { Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network); } } - if (NOT_STARTED != mStartedState) { - mStartedState = STOPPING; - Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name()); - if (mType == TYPE_NATT) { - mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); - } else if (mType == TYPE_TCP) { - mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); - mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, mSlot); - mTcpController.stopSocketMonitor(mSlot); - } else { - Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType); - } + Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name() + ": " + reason); + switch (mStartedState) { + case NOT_STARTED: + // Remove the reference of the keepalive that meet error before starting, + // e.g. invalid parameter. + cleanupStoppedKeepalive(mNai, mSlot); + break; + case STOPPING: + // Keepalive is already in stopping state, ignore. + return; + default: + mStartedState = STOPPING; + if (mType == TYPE_NATT) { + mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); + } else if (mType == TYPE_TCP) { + mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); + mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, mSlot); + mTcpController.stopSocketMonitor(mSlot); + } else { + Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType); + } } // Close the duplicated fd that maintains the lifecycle of socket whenever @@ -453,9 +463,9 @@ public class KeepaliveTracker { for (KeepaliveInfo ki : networkKeepalives.values()) { ki.stop(reason); } - networkKeepalives.clear(); - mKeepalives.remove(nai); } + // Clean up keepalives will be done as a result of calling ki.stop() after the slots are + // freed. } public void handleStopKeepalive(NetworkAgentInfo nai, int slot, int reason) { @@ -471,8 +481,24 @@ public class KeepaliveTracker { return; } ki.stop(reason); + // Clean up keepalives will be done as a result of calling ki.stop() after the slots are + // freed. + } + + private void cleanupStoppedKeepalive(NetworkAgentInfo nai, int slot) { + String networkName = (nai == null) ? "(null)" : nai.name(); + HashMap networkKeepalives = mKeepalives.get(nai); + if (networkKeepalives == null) { + Log.e(TAG, "Attempt to remove keepalive on nonexistent network " + networkName); + return; + } + KeepaliveInfo ki = networkKeepalives.get(slot); + if (ki == null) { + Log.e(TAG, "Attempt to remove nonexistent keepalive " + slot + " on " + networkName); + return; + } networkKeepalives.remove(slot); - Log.d(TAG, "Stopped keepalive " + slot + " on " + networkName + ", " + Log.d(TAG, "Remove keepalive " + slot + " on " + networkName + ", " + networkKeepalives.size() + " remains."); if (networkKeepalives.isEmpty()) { mKeepalives.remove(nai); @@ -543,10 +569,11 @@ public class KeepaliveTracker { handleStopKeepalive(nai, slot, reason); } } else if (KeepaliveInfo.STOPPING == ki.mStartedState) { - // The message indicated result of stopping : don't call handleStopKeepalive. + // The message indicated result of stopping : clean up keepalive slots. Log.d(TAG, "Stopped keepalive " + slot + " on " + nai.name() + " stopped: " + reason); ki.mStartedState = KeepaliveInfo.NOT_STARTED; + cleanupStoppedKeepalive(nai, slot); } else { Log.wtf(TAG, "Event " + message.what + "," + slot + "," + reason + " for keepalive in wrong state: " + ki.toString()); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index fe1378736e..b0cc20785c 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -4342,8 +4342,9 @@ public class ConnectivityServiceTest { } // Check that there is no port leaked after all keepalives and sockets are closed. - assertFalse(isUdpPortInUse(srcPort)); - assertFalse(isUdpPortInUse(srcPort2)); + // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7. + // assertFalse(isUdpPortInUse(srcPort)); + // assertFalse(isUdpPortInUse(srcPort2)); mWiFiNetworkAgent.disconnect(); waitFor(mWiFiNetworkAgent.getDisconnectedCV()); @@ -4471,7 +4472,8 @@ public class ConnectivityServiceTest { assertEquals(anyIPv4, sa.getAddress()); testPfd.close(); - assertFalse(isUdpPortInUse(srcPort)); + // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7. + // assertFalse(isUdpPortInUse(srcPort)); mWiFiNetworkAgent.disconnect(); waitFor(mWiFiNetworkAgent.getDisconnectedCV()); From 2c849187292cf65064a74fe89bea9774072c003c Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 9 May 2019 13:24:32 -0700 Subject: [PATCH 079/130] Clean up the keepalive slots when network disconnect In general, keepalive slots are released after result of stopping has returned. However, for network disconnect case, the service side cannot communicate with network agent since the async channel is broken. Clean up keepalive slots right after stop in this case. Bug: 132341736 Test: 1. atest com.android.server.ConnectivityServiceTest \ #testNattSocketKeepalives --generate-new-metrics 100 2. atest FrameworksNetTests --generate-new-metrics 10 Change-Id: Id3e4e159713c0ed7e03f45169e87b73ae6408e4f (cherry picked from commit a5f6bd16062fba89bcf900aca93aa3514d93f662) Merged-In: Id3e4e159713c0ed7e03f45169e87b73ae6408e4f Merged-In: Icb5a1b5bb10617aa5a7b35db6cf48db3dc53b7fd --- .../java/com/android/server/connectivity/KeepaliveTracker.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index ae58e994a5..7fb97f28ea 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -462,6 +462,9 @@ public class KeepaliveTracker { if (networkKeepalives != null) { for (KeepaliveInfo ki : networkKeepalives.values()) { ki.stop(reason); + // Clean up keepalives since the network agent is disconnected and unable to pass + // back asynchronous result of stop(). + cleanupStoppedKeepalive(nai, ki.mSlot); } } // Clean up keepalives will be done as a result of calling ki.stop() after the slots are From 714801ec757433578c833e4359b9ed22fac0af1e Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 13 May 2019 14:19:00 +0800 Subject: [PATCH 080/130] Fix concurrent modification exception in KeepaliveTracker In aosp/951200, the clean up function delete the item in the hash map that holds the record while iterating it, where the list used to iterate the records is backed by the hash map, so changes to the map are reflected in the list and caused the concurrent modification exception. Bug: 132341736 Test: 1. atest com.android.server.ConnectivityServiceTest \ #testNattSocketKeepalives --generate-new-metrics 300 2. atest FrameworksNetTests --generate-new-metrics 10 (Clean cherry-pick of aosp/959599) Change-Id: I9cdfe6f6d11c5400c856cc30a33ff4a44ba9d811 Merged-In: I0481a469ee23231e5f0ab738a06b5e09f6cdb680 --- .../com/android/server/connectivity/KeepaliveTracker.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 7fb97f28ea..0edab4fe3c 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -458,9 +458,10 @@ public class KeepaliveTracker { } public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) { - HashMap networkKeepalives = mKeepalives.get(nai); + final HashMap networkKeepalives = mKeepalives.get(nai); if (networkKeepalives != null) { - for (KeepaliveInfo ki : networkKeepalives.values()) { + final ArrayList kalist = new ArrayList(networkKeepalives.values()); + for (KeepaliveInfo ki : kalist) { ki.stop(reason); // Clean up keepalives since the network agent is disconnected and unable to pass // back asynchronous result of stop(). From 4f4d8cb417bcfb7619bb20b561066c146682062e Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 2 May 2019 21:14:20 +0800 Subject: [PATCH 081/130] Send message to add/remove NAT-T keepalive packet filter. Remove definition of TYPE_NATT and TYPE_TCP since the type can be identified by checking message.obj is an instance of NattKeepalivePacketData or TcpKeepalivePacketData. It's more simple and won't have dependency on KeepaliveInfo. Bug: 33530442 Test: atest FrameworksNetTests atest NetworkStackTests (Clean cherry-pick of aosp/955419) Change-Id: Ic97ffe9ff5781778efd264460809f5059f0f4230 Merged-In: Ic97ffe9ff5781778efd264460809f5059f0f4230 --- .../server/connectivity/KeepaliveTracker.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 0edab4fe3c..3de2537cff 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -327,6 +327,8 @@ public class KeepaliveTracker { Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name()); switch (mType) { case TYPE_NATT: + mNai.asyncChannel.sendMessage( + CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, mPacket); mNai.asyncChannel .sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket); break; @@ -337,9 +339,8 @@ public class KeepaliveTracker { handleStopKeepalive(mNai, mSlot, ERROR_INVALID_SOCKET); return; } - mNai.asyncChannel - .sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, - mPacket); + mNai.asyncChannel.sendMessage( + CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */, mPacket); // TODO: check result from apf and notify of failure as needed. mNai.asyncChannel .sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket); @@ -375,14 +376,17 @@ public class KeepaliveTracker { return; default: mStartedState = STOPPING; - if (mType == TYPE_NATT) { - mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); - } else if (mType == TYPE_TCP) { - mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); - mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, mSlot); - mTcpController.stopSocketMonitor(mSlot); - } else { - Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType); + switch (mType) { + case TYPE_TCP: + mTcpController.stopSocketMonitor(mSlot); + // fall through + case TYPE_NATT: + mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); + mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, + mSlot); + break; + default: + Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType); } } From 2bebfc2b87698f664575bce04e4a7d1d9844fd98 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Fri, 19 Apr 2019 16:05:03 -0700 Subject: [PATCH 082/130] Clean up the permission control code in framework Delete the unused NetworkManagementService API for set/remove permissions. Use PERMISSION_NONE to replace NO_PERMISSIONS so the framework now use the same set of permission constant when communicate with netd. Bug: 128944261 Test: PermissionMonitorTest.java Change-Id: I25224c9576f52d2a0a0bd2182325c7aac7b28eb5 Merged-In: I25224c9576f52d2a0a0bd2182325c7aac7b28eb5 (cherry picked from commit 05887f99c6ca6885db737af2f356023dc6de80a2) --- .../android/server/connectivity/PermissionMonitor.java | 4 ++-- .../server/connectivity/PermissionMonitorTest.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index f8582cd792..d05369e9cf 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -650,7 +650,7 @@ public class PermissionMonitor { case INetd.PERMISSION_UPDATE_DEVICE_STATS: updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); break; - case INetd.NO_PERMISSIONS: + case INetd.PERMISSION_NONE: noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); break; case INetd.PERMISSION_UNINSTALLED: @@ -676,7 +676,7 @@ public class PermissionMonitor { ArrayUtils.convertToIntArray(updateStatsPermissionAppIds)); } if (noPermissionAppIds.size() != 0) { - mNetd.trafficSetNetPermForUids(INetd.NO_PERMISSIONS, + mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE, ArrayUtils.convertToIntArray(noPermissionAppIds)); } if (uninstalledAppIds.size() != 0) { diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index 62a4718965..df1f57f7a0 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -524,7 +524,7 @@ public class PermissionMonitorTest { SparseIntArray netdPermissionsAppIds = new SparseIntArray(); netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET); - netdPermissionsAppIds.put(MOCK_UID2, INetd.NO_PERMISSIONS); + netdPermissionsAppIds.put(MOCK_UID2, INetd.PERMISSION_NONE); netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS); netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS); @@ -534,7 +534,7 @@ public class PermissionMonitorTest { mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); - mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{MOCK_UID2}); + mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2}); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1}); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS, @@ -553,8 +553,8 @@ public class PermissionMonitorTest { mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2}); // Revoke permission from SYSTEM_UID1, expect no permission stored. - mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.NO_PERMISSIONS); - mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{SYSTEM_UID1}); + mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE); + mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1}); } private PackageInfo addPackage(String packageName, int uid, String[] permissions) From 49ea93861d1bee28c9acee421b11364c401751de Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Tue, 14 May 2019 04:28:35 -0700 Subject: [PATCH 083/130] Fix captive portal app can be launched w/o MAINLINE_NETWORK_STACK permission Caller should get SecurityException if called ConnectivityManager#startCaptivePortalApp() w/o MAINLINE_NETWORK_STACK permission. But now it will not get any exception and can launch captive portal app successfully. Bug: 132662433 Test: atest android.net.cts.ConnectivityManagerTest#testStartCaptivePortalApp w and w/o MAINLINE_NETWORK_STACK permission Test: atest FrameworksNetTests NetworkStackTests Change-Id: Ib70fe6fad107f3e9dce9ce673188c5ce5dc1ad7b Merged-In: I1025da29beb53259f57bd9ca5648b32f2847ed4a Merged-In: Ib70fe6fad107f3e9dce9ce673188c5ce5dc1ad7b (cherry picked from commit 72b3ab18ca302a3117f424a0f0ef6c08897c310e) --- services/core/java/com/android/server/ConnectivityService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index facc299450..f12bfc33ea 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3497,7 +3497,8 @@ public class ConnectivityService extends IConnectivityManager.Stub */ @Override public void startCaptivePortalAppInternal(Network network, Bundle appExtras) { - mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); + mContext.enforceCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + "ConnectivityService"); final Intent appIntent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); appIntent.putExtras(appExtras); From 5688ce39c4e4f1510e2d41d871c6e7c43012c34c Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Tue, 14 May 2019 22:41:10 -0700 Subject: [PATCH 084/130] Ignore NetworkTest when running CtsNetTestCases in instant app mode Ignore NetworkTest#testBindSocketOfConnectedDatagramSocketThrows when running CtsNetTestCases in instant app mode due to sockect cannot bind in instant app mode. Bug: 123366918 Test: atest CtsNetTestCases --instant Test: atest FrameworksNetTests Change-Id: I1e93d4491e3d9e5a095ff4b6169b2f70e7b3b690 Merged-In: Ia28eea113e19b9c44998677e5b8093be178a06a3 Merged-In: I1e93d4491e3d9e5a095ff4b6169b2f70e7b3b690 (cherry picked from commit 73c0d48b14488c93b2f42a1e149e4be8499d3469) --- tests/net/common/Android.bp | 1 + tests/net/common/java/android/net/NetworkTest.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp index 07525a6ea4..db1ccb446c 100644 --- a/tests/net/common/Android.bp +++ b/tests/net/common/Android.bp @@ -24,6 +24,7 @@ java_library { "frameworks-net-testutils", "junit", "mockito-target-minus-junit4", + "platform-test-annotations", ], libs: [ "android.test.base.stubs", diff --git a/tests/net/common/java/android/net/NetworkTest.java b/tests/net/common/java/android/net/NetworkTest.java index bef66b27df..38bc744a0a 100644 --- a/tests/net/common/java/android/net/NetworkTest.java +++ b/tests/net/common/java/android/net/NetworkTest.java @@ -25,6 +25,7 @@ import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.net.Network; +import android.platform.test.annotations.AppModeFull; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -74,6 +75,7 @@ public class NetworkTest { } @Test + @AppModeFull(reason = "Socket cannot bind in instant app mode") public void testBindSocketOfConnectedDatagramSocketThrows() throws Exception { final DatagramSocket mDgramSocket = new DatagramSocket(0, (InetAddress) Inet6Address.ANY); mDgramSocket.connect((InetAddress) Inet6Address.LOOPBACK, 53); From 30dfd6ecfa91a8811de61e47131702c90f5b8236 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 10 May 2019 18:56:55 -0700 Subject: [PATCH 085/130] Clean up the arguments annotation and verify items on IpMemoryStoreTest. Bug: 131133347 Test: atest FrameworksNetTests Merged-In: I8ce3bed435fbbb814d71fe48ffd305ff3f947f3f Merged-In: I1db13a48b59d743482436ecf8a20d7f12edd6e1c (cherry picked from commit 7567c4ac50508c2bcd38b37fc48b299912a34cf5) Change-Id: I78024c0e25d812639d1236faa59d383742ae2141 --- .../java/android/net/IpMemoryStoreTest.java | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java index 8ff2de9777..6e69b34fe4 100644 --- a/tests/net/java/android/net/IpMemoryStoreTest.java +++ b/tests/net/java/android/net/IpMemoryStoreTest.java @@ -111,13 +111,12 @@ public class IpMemoryStoreTest { @Test public void testNetworkAttributes() throws Exception { - startIpMemoryStore(true); + startIpMemoryStore(true /* supplyService */); final String l2Key = "fakeKey"; mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, - status -> { - assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); - }); + status -> assertTrue("Store not successful : " + status.resultCode, + status.isSuccess())); verify(mMockService, times(1)).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any()); assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); @@ -135,7 +134,7 @@ public class IpMemoryStoreTest { @Test public void testPrivateData() throws RemoteException { - startIpMemoryStore(true); + startIpMemoryStore(true /* supplyService */); final Blob b = new Blob(); b.data = TEST_BLOB_DATA; final String l2Key = "fakeKey"; @@ -162,7 +161,7 @@ public class IpMemoryStoreTest { @Test public void testFindL2Key() throws UnknownHostException, RemoteException, Exception { - startIpMemoryStore(true); + startIpMemoryStore(true /* supplyService */); final String l2Key = "fakeKey"; mStore.findL2Key(TEST_NETWORK_ATTRIBUTES, @@ -177,7 +176,7 @@ public class IpMemoryStoreTest { @Test public void testIsSameNetwork() throws UnknownHostException, RemoteException { - startIpMemoryStore(true); + startIpMemoryStore(true /* supplyService */); final String l2Key1 = "fakeKey1"; final String l2Key2 = "fakeKey2"; @@ -193,7 +192,7 @@ public class IpMemoryStoreTest { @Test public void testEnqueuedIpMsRequests() throws Exception { - startIpMemoryStore(false); + startIpMemoryStore(false /* supplyService */); final Blob b = new Blob(); b.data = TEST_BLOB_DATA; @@ -201,9 +200,8 @@ public class IpMemoryStoreTest { // enqueue multiple ipms requests mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, - status -> { - assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); - }); + status -> assertTrue("Store not successful : " + status.resultCode, + status.isSuccess())); mStore.retrieveNetworkAttributes(l2Key, (status, key, attr) -> { assertTrue("Retrieve network attributes not successful : " @@ -212,9 +210,8 @@ public class IpMemoryStoreTest { assertEquals(TEST_NETWORK_ATTRIBUTES, attr); }); mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b, - status -> { - assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); - }); + status -> assertTrue("Store not successful : " + status.resultCode, + status.isSuccess())); mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME, (status, key, name, data) -> { assertTrue("Retrieve blob status not successful : " + status.resultCode, @@ -240,7 +237,7 @@ public class IpMemoryStoreTest { @Test public void testEnqueuedIpMsRequestsWithException() throws Exception { - startIpMemoryStore(true); + startIpMemoryStore(true /* supplyService */); doThrow(RemoteException.class).when(mMockService).retrieveNetworkAttributes(any(), any()); final Blob b = new Blob(); @@ -249,9 +246,8 @@ public class IpMemoryStoreTest { // enqueue multiple ipms requests mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, - status -> { - assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); - }); + status -> assertTrue("Store not successful : " + status.resultCode, + status.isSuccess())); mStore.retrieveNetworkAttributes(l2Key, (status, key, attr) -> { assertTrue("Retrieve network attributes not successful : " @@ -260,9 +256,8 @@ public class IpMemoryStoreTest { assertEquals(TEST_NETWORK_ATTRIBUTES, attr); }); mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b, - status -> { - assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); - }); + status -> assertTrue("Store not successful : " + status.resultCode, + status.isSuccess())); mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME, (status, key, name, data) -> { assertTrue("Retrieve blob status not successful : " + status.resultCode, @@ -286,7 +281,7 @@ public class IpMemoryStoreTest { @Test public void testEnqueuedIpMsRequestsCallbackFunctionWithException() throws Exception { - startIpMemoryStore(true); + startIpMemoryStore(true /* supplyService */); final Blob b = new Blob(); b.data = TEST_BLOB_DATA; @@ -294,9 +289,8 @@ public class IpMemoryStoreTest { // enqueue multiple ipms requests mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES, - status -> { - assertTrue("Store not successful : " + status.resultCode, status.isSuccess()); - }); + status -> assertTrue("Store not successful : " + status.resultCode, + status.isSuccess())); mStore.retrieveNetworkAttributes(l2Key, (status, key, attr) -> { throw new RuntimeException("retrieveNetworkAttributes test"); @@ -320,6 +314,7 @@ public class IpMemoryStoreTest { inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any()); + inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any()); inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME), eq(b), any()); inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID), From ee5282105cb53bfdafb1428835b4aabfb26b7ac8 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 16 May 2019 23:16:56 -0700 Subject: [PATCH 086/130] Change the icon for the LOGGED_IN notification. This notification is shown when the user has already logged in to the network, so it should not have a question mark on it. Fix: 130526201 Test: atest FrameworksNetTests Test: manually signed in to portal Change-Id: I8250236bc4ba251492a6cb9bf23e67666ef860d3 Merged-In: I8250236bc4ba251492a6cb9bf23e67666ef860d3 (cherry picked from commit fce363555029b92b1532058555797d6ef1afb09c) --- .../connectivity/NetworkNotificationManager.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index ac3d6def6f..0910dac273 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -19,7 +19,6 @@ package com.android.server.connectivity; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; -import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; import android.app.Notification; import android.app.NotificationManager; @@ -107,10 +106,14 @@ public class NetworkNotificationManager { } } - private static int getIcon(int transportType) { - return (transportType == TRANSPORT_WIFI) ? - R.drawable.stat_notify_wifi_in_range : // TODO: Distinguish ! from ?. - R.drawable.stat_notify_rssi_in_range; + private static int getIcon(int transportType, NotificationType notifyType) { + if (transportType != TRANSPORT_WIFI) { + return R.drawable.stat_notify_rssi_in_range; + } + + return notifyType == NotificationType.LOGGED_IN + ? R.drawable.ic_wifi_signal_4 + : R.drawable.stat_notify_wifi_in_range; // TODO: Distinguish ! from ?. } /** @@ -127,6 +130,7 @@ public class NetworkNotificationManager { * @param id an identifier that uniquely identifies this notification. This must match * between show and hide calls. We use the NetID value but for legacy callers * we concatenate the range of types with the range of NetIDs. + * @param notifyType the type of the notification. * @param nai the network with which the notification is associated. For a SIGN_IN, NO_INTERNET, * or LOST_INTERNET notification, this is the network we're connecting to. For a * NETWORK_SWITCH notification it's the network that we switched from. When this network @@ -173,7 +177,7 @@ public class NetworkNotificationManager { Resources r = Resources.getSystem(); CharSequence title; CharSequence details; - int icon = getIcon(transportType); + int icon = getIcon(transportType, notifyType); if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) { title = r.getString(R.string.wifi_no_internet, WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); From 6f1f2df72bb049a82e072c468c864507a0b6b071 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 22 May 2019 02:42:25 -0700 Subject: [PATCH 087/130] Let clients access StaticIpConfiguration members through reflection. Bug: 131764329 Test: none Change-Id: Ice5c4fd4d469a55410129310c5a25874b94e2219 (cherry picked from commit 6736fb0465e3cc9f38ee1340e6b831a6dcd195e8) Merged-In: I0fa84390f6c289571afa9d86cb922835fe2b7e77 --- core/java/android/net/StaticIpConfiguration.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java index 87f8739a5b..fe42111afb 100644 --- a/core/java/android/net/StaticIpConfiguration.java +++ b/core/java/android/net/StaticIpConfiguration.java @@ -58,15 +58,15 @@ public final class StaticIpConfiguration implements Parcelable { @Nullable public LinkAddress ipAddress; /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @UnsupportedAppUsage @Nullable public InetAddress gateway; /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @UnsupportedAppUsage @NonNull public final ArrayList dnsServers; /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @UnsupportedAppUsage @Nullable public String domains; From 8ad1afb8f8f25050e349d7999b4bfb40a06e0852 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 22 May 2019 02:55:10 -0700 Subject: [PATCH 088/130] Update throws documentation for requestNetwork* Bug: 78126688 Test: builds Change-Id: Iaabcc52b3e6537752990b88a24e11217f73ce8e7 (cherry picked from commit 75f1329f927202f39ae29d2acaad97d01f5c8cb8) Merged-In: I8b5bb052bf73feed0dfafafaf44fcd07f58186ce --- .../java/android/net/ConnectivityManager.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index a69ca99500..3bc40a7999 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -3612,8 +3612,9 @@ public class ConnectivityManager { * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note * the callback must not be shared - it uniquely specifies this request. * The callback is invoked on the default internal Handler. - * @throws IllegalArgumentException if {@code request} specifies any mutable - * {@code NetworkCapabilities}. + * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. + * @throws SecurityException if missing the appropriate permissions. + * @throws RuntimeException if request limit per UID is exceeded. */ public void requestNetwork(@NonNull NetworkRequest request, @NonNull NetworkCallback networkCallback) { @@ -3648,8 +3649,9 @@ public class ConnectivityManager { * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note * the callback must not be shared - it uniquely specifies this request. * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. - * @throws IllegalArgumentException if {@code request} specifies any mutable - * {@code NetworkCapabilities}. + * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. + * @throws SecurityException if missing the appropriate permissions. + * @throws RuntimeException if request limit per UID is exceeded. */ public void requestNetwork(@NonNull NetworkRequest request, @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { @@ -3685,6 +3687,9 @@ public class ConnectivityManager { * @param timeoutMs The time in milliseconds to attempt looking for a suitable network * before {@link NetworkCallback#onUnavailable()} is called. The timeout must * be a positive value (i.e. >0). + * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. + * @throws SecurityException if missing the appropriate permissions. + * @throws RuntimeException if request limit per UID is exceeded. */ public void requestNetwork(@NonNull NetworkRequest request, @NonNull NetworkCallback networkCallback, int timeoutMs) { @@ -3719,6 +3724,9 @@ public class ConnectivityManager { * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. * @param timeoutMs The time in milliseconds to attempt looking for a suitable network * before {@link NetworkCallback#onUnavailable} is called. + * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. + * @throws SecurityException if missing the appropriate permissions. + * @throws RuntimeException if request limit per UID is exceeded. */ public void requestNetwork(@NonNull NetworkRequest request, @NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) { @@ -3789,9 +3797,9 @@ public class ConnectivityManager { * @param operation Action to perform when the network is available (corresponds * to the {@link NetworkCallback#onAvailable} call. Typically * comes from {@link PendingIntent#getBroadcast}. Cannot be null. - * @throws IllegalArgumentException if {@code request} contains either - * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or - * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}. + * @throws IllegalArgumentException if {@code request} contains invalid network capabilities. + * @throws SecurityException if missing the appropriate permissions. + * @throws RuntimeException if request limit per UID is exceeded. */ public void requestNetwork(@NonNull NetworkRequest request, @NonNull PendingIntent operation) { From 781db272f3feaa1fa41f46c26eab18b143e687c4 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 22 May 2019 01:20:45 -0700 Subject: [PATCH 089/130] Properly use versioned interfaces. Our stable AIDL interfaces need to use versioned build targets, otherwise getVersion will always return 0, which makes it impossible to support different components at different versions. List generated with: find . -name Android.bp -exec egrep \ -H "(netd|dnsresolver|ipmemorystore|networkstack).aidl.interface(s?)-(java|cpp)" {} \; \ | grep -v oemnetd | grep -v tests/ Test: m Bug: 133124190 (cherry-pick from aosp/968011) Merged-In: Idf49e840263ef32b9ee4fafa6718d4f893ea7c87 (cherry picked from commit 433f7c4178aaadac7d6a5f6727f39ef83342d436) Change-Id: I77e2291b52fda24ee01e1b22ddafe4fe7368959e --- tests/net/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/net/Android.bp b/tests/net/Android.bp index 1fbb6580c3..306cc515c8 100644 --- a/tests/net/Android.bp +++ b/tests/net/Android.bp @@ -56,7 +56,7 @@ java_defaults { "libutilscallstack", "libziparchive", "libz", - "netd_aidl_interface-cpp", + "netd_aidl_interface-V2-cpp", "libnetworkstatsfactorytestjni", ], } From 51b9f6c069d6ff392c5fdd063d062a4ab97a22d9 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Thu, 23 May 2019 06:14:28 -0700 Subject: [PATCH 090/130] Add Rfc6724 style sort for DnsResolver and fix potential bug 1. pass default network explicitly to fix potential mis-sync network problem in DnsResolver#query 2. Add rfc6724 sort and related test 3. DnsResolver do rfc6724 sort before response InetAddress answers 4. move haveIpv* function from DnsResolver to DnsUtils Bug: 129530368 Test: atest DnsResolverTest DnsUtilsTest Merged-In: I0323f5c7f32fc3fa589b9e87f8e7c9caf744dbd4 (cherry picked from commit d352f4ca85ff8418a5a58d32fb03b85d7e0b843b) Change-Id: I98455045fa43cc5a5902a08232251c1734feaac3 --- core/java/android/net/DnsResolver.java | 106 ++--- core/java/android/net/NetworkUtils.java | 7 + core/java/android/net/util/DnsUtils.java | 376 ++++++++++++++++++ core/jni/android_net_NetUtils.cpp | 29 +- .../java/android/net/util/DnsUtilsTest.java | 221 ++++++++++ 5 files changed, 666 insertions(+), 73 deletions(-) create mode 100644 core/java/android/net/util/DnsUtils.java create mode 100644 tests/net/java/android/net/util/DnsUtilsTest.java diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java index 68826cbeb8..4b2b4c35b2 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -16,16 +16,17 @@ package android.net; +import static android.net.NetworkUtils.getDnsNetId; import static android.net.NetworkUtils.resNetworkCancel; import static android.net.NetworkUtils.resNetworkQuery; import static android.net.NetworkUtils.resNetworkResult; import static android.net.NetworkUtils.resNetworkSend; +import static android.net.util.DnsUtils.haveIpv4; +import static android.net.util.DnsUtils.haveIpv6; +import static android.net.util.DnsUtils.rfc6724Sort; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; -import static android.system.OsConstants.IPPROTO_UDP; -import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.ENONET; import android.annotation.CallbackExecutor; import android.annotation.IntDef; @@ -34,18 +35,12 @@ import android.annotation.Nullable; import android.os.CancellationSignal; import android.os.Looper; import android.system.ErrnoException; -import android.system.Os; import android.util.Log; -import libcore.io.IoUtils; - import java.io.FileDescriptor; -import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; @@ -196,8 +191,8 @@ public final class DnsResolver { final Object lock = new Object(); final FileDescriptor queryfd; try { - queryfd = resNetworkSend((network != null - ? network.getNetIdForResolv() : NETID_UNSET), query, query.length, flags); + queryfd = resNetworkSend((network != null) + ? network.getNetIdForResolv() : NETID_UNSET, query, query.length, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -237,8 +232,8 @@ public final class DnsResolver { final Object lock = new Object(); final FileDescriptor queryfd; try { - queryfd = resNetworkQuery((network != null - ? network.getNetIdForResolv() : NETID_UNSET), domain, nsClass, nsType, flags); + queryfd = resNetworkQuery((network != null) + ? network.getNetIdForResolv() : NETID_UNSET, domain, nsClass, nsType, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -252,14 +247,16 @@ public final class DnsResolver { private class InetAddressAnswerAccumulator implements Callback { private final List mAllAnswers; + private final Network mNetwork; private int mRcode; private DnsException mDnsException; private final Callback> mUserCallback; private final int mTargetAnswerCount; private int mReceivedAnswerCount = 0; - InetAddressAnswerAccumulator(int size, + InetAddressAnswerAccumulator(@NonNull Network network, int size, @NonNull Callback> callback) { + mNetwork = network; mTargetAnswerCount = size; mAllAnswers = new ArrayList<>(); mUserCallback = callback; @@ -280,8 +277,7 @@ public final class DnsResolver { private void maybeReportAnswer() { if (++mReceivedAnswerCount != mTargetAnswerCount) return; if (mAllAnswers.isEmpty() && maybeReportError()) return; - // TODO: Do RFC6724 sort. - mUserCallback.onAnswer(mAllAnswers, mRcode); + mUserCallback.onAnswer(rfc6724Sort(mNetwork, mAllAnswers), mRcode); } @Override @@ -308,7 +304,7 @@ public final class DnsResolver { /** * Send a DNS query with the specified name on a network with both IPv4 and IPv6, - * get back a set of InetAddresses asynchronously. + * get back a set of InetAddresses with rfc6724 sorting style asynchronously. * * This method will examine the connection ability on given network, and query IPv4 * and IPv6 if connection is available. @@ -335,8 +331,23 @@ public final class DnsResolver { return; } final Object lock = new Object(); - final boolean queryIpv6 = haveIpv6(network); - final boolean queryIpv4 = haveIpv4(network); + final Network queryNetwork; + try { + queryNetwork = (network != null) ? network : new Network(getDnsNetId()); + } catch (ErrnoException e) { + executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); + return; + } + final boolean queryIpv6 = haveIpv6(queryNetwork); + final boolean queryIpv4 = haveIpv4(queryNetwork); + + // This can only happen if queryIpv4 and queryIpv6 are both false. + // This almost certainly means that queryNetwork does not exist or no longer exists. + if (!queryIpv6 && !queryIpv4) { + executor.execute(() -> callback.onError( + new DnsException(ERROR_SYSTEM, new ErrnoException("resNetworkQuery", ENONET)))); + return; + } final FileDescriptor v4fd; final FileDescriptor v6fd; @@ -345,9 +356,8 @@ public final class DnsResolver { if (queryIpv6) { try { - v6fd = resNetworkQuery((network != null - ? network.getNetIdForResolv() : NETID_UNSET), - domain, CLASS_IN, TYPE_AAAA, flags); + v6fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, + TYPE_AAAA, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -355,7 +365,6 @@ public final class DnsResolver { queryCount++; } else v6fd = null; - // TODO: Use device flag to control the sleep time. // Avoiding gateways drop packets if queries are sent too close together try { Thread.sleep(SLEEP_TIME_MS); @@ -365,9 +374,8 @@ public final class DnsResolver { if (queryIpv4) { try { - v4fd = resNetworkQuery((network != null - ? network.getNetIdForResolv() : NETID_UNSET), - domain, CLASS_IN, TYPE_A, flags); + v4fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, TYPE_A, + flags); } catch (ErrnoException e) { if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid. executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); @@ -377,7 +385,7 @@ public final class DnsResolver { } else v4fd = null; final InetAddressAnswerAccumulator accumulator = - new InetAddressAnswerAccumulator(queryCount, callback); + new InetAddressAnswerAccumulator(queryNetwork, queryCount, callback); synchronized (lock) { if (queryIpv6) { @@ -398,7 +406,7 @@ public final class DnsResolver { /** * Send a DNS query with the specified name and query type, get back a set of - * InetAddresses asynchronously. + * InetAddresses with rfc6724 sorting style asynchronously. * * The answer will be provided asynchronously through the provided {@link Callback}. * @@ -423,15 +431,17 @@ public final class DnsResolver { } final Object lock = new Object(); final FileDescriptor queryfd; + final Network queryNetwork; try { - queryfd = resNetworkQuery((network != null - ? network.getNetIdForResolv() : NETID_UNSET), domain, CLASS_IN, nsType, flags); + queryNetwork = (network != null) ? network : new Network(getDnsNetId()); + queryfd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, nsType, + flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; } final InetAddressAnswerAccumulator accumulator = - new InetAddressAnswerAccumulator(1, callback); + new InetAddressAnswerAccumulator(queryNetwork, 1, callback); synchronized (lock) { registerFDListener(executor, queryfd, accumulator, cancellationSignal, lock); if (cancellationSignal == null) return; @@ -500,38 +510,6 @@ public final class DnsResolver { }); } - // These two functions match the behaviour of have_ipv4 and have_ipv6 in the native resolver. - private boolean haveIpv4(@Nullable Network network) { - final SocketAddress addrIpv4 = - new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0); - return checkConnectivity(network, AF_INET, addrIpv4); - } - - private boolean haveIpv6(@Nullable Network network) { - final SocketAddress addrIpv6 = - new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0); - return checkConnectivity(network, AF_INET6, addrIpv6); - } - - private boolean checkConnectivity(@Nullable Network network, - int domain, @NonNull SocketAddress addr) { - final FileDescriptor socket; - try { - socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP); - } catch (ErrnoException e) { - return false; - } - try { - if (network != null) network.bindSocket(socket); - Os.connect(socket, addr); - } catch (IOException | ErrnoException e) { - return false; - } finally { - IoUtils.closeQuietly(socket); - } - return true; - } - private static class DnsAddressAnswer extends DnsPacket { private static final String TAG = "DnsResolver.DnsAddressAnswer"; private static final boolean DBG = false; diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index c06a13269d..a640f83ea5 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -156,6 +156,13 @@ public class NetworkUtils { */ public static native void resNetworkCancel(FileDescriptor fd); + /** + * DNS resolver series jni method. + * Attempts to get netid of network which resolver will + * use if no network is explicitly selected. + */ + public static native int getDnsNetId() throws ErrnoException; + /** * Get the tcp repair window associated with the {@code fd}. * diff --git a/core/java/android/net/util/DnsUtils.java b/core/java/android/net/util/DnsUtils.java new file mode 100644 index 0000000000..e6abd50590 --- /dev/null +++ b/core/java/android/net/util/DnsUtils.java @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2019 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.util; + +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.IPPROTO_UDP; +import static android.system.OsConstants.SOCK_DGRAM; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.InetAddresses; +import android.net.Network; +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import com.android.internal.util.BitUtils; + +import libcore.io.IoUtils; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * @hide + */ +public class DnsUtils { + private static final String TAG = "DnsUtils"; + private static final int CHAR_BIT = 8; + public static final int IPV6_ADDR_SCOPE_NODELOCAL = 0x01; + public static final int IPV6_ADDR_SCOPE_LINKLOCAL = 0x02; + public static final int IPV6_ADDR_SCOPE_SITELOCAL = 0x05; + public static final int IPV6_ADDR_SCOPE_GLOBAL = 0x0e; + private static final Comparator sRfc6724Comparator = new Rfc6724Comparator(); + + /** + * Comparator to sort SortableAddress in Rfc6724 style. + */ + public static class Rfc6724Comparator implements Comparator { + // This function matches the behaviour of _rfc6724_compare in the native resolver. + @Override + public int compare(SortableAddress span1, SortableAddress span2) { + // Rule 1: Avoid unusable destinations. + if (span1.hasSrcAddr != span2.hasSrcAddr) { + return span2.hasSrcAddr - span1.hasSrcAddr; + } + + // Rule 2: Prefer matching scope. + if (span1.scopeMatch != span2.scopeMatch) { + return span2.scopeMatch - span1.scopeMatch; + } + + // TODO: Implement rule 3: Avoid deprecated addresses. + // TODO: Implement rule 4: Prefer home addresses. + + // Rule 5: Prefer matching label. + if (span1.labelMatch != span2.labelMatch) { + return span2.labelMatch - span1.labelMatch; + } + + // Rule 6: Prefer higher precedence. + if (span1.precedence != span2.precedence) { + return span2.precedence - span1.precedence; + } + + // TODO: Implement rule 7: Prefer native transport. + + // Rule 8: Prefer smaller scope. + if (span1.scope != span2.scope) { + return span1.scope - span2.scope; + } + + // Rule 9: Use longest matching prefix. IPv6 only. + if (span1.prefixMatchLen != span2.prefixMatchLen) { + return span2.prefixMatchLen - span1.prefixMatchLen; + } + + // Rule 10: Leave the order unchanged. Collections.sort is a stable sort. + return 0; + } + } + + /** + * Class used to sort with RFC 6724 + */ + public static class SortableAddress { + public final int label; + public final int labelMatch; + public final int scope; + public final int scopeMatch; + public final int precedence; + public final int prefixMatchLen; + public final int hasSrcAddr; + public final InetAddress address; + + public SortableAddress(@NonNull InetAddress addr, @Nullable InetAddress srcAddr) { + address = addr; + hasSrcAddr = (srcAddr != null) ? 1 : 0; + label = findLabel(addr); + scope = findScope(addr); + precedence = findPrecedence(addr); + labelMatch = ((srcAddr != null) && (label == findLabel(srcAddr))) ? 1 : 0; + scopeMatch = ((srcAddr != null) && (scope == findScope(srcAddr))) ? 1 : 0; + if (isIpv6Address(addr) && isIpv6Address(srcAddr)) { + prefixMatchLen = compareIpv6PrefixMatchLen(srcAddr, addr); + } else { + prefixMatchLen = 0; + } + } + } + + /** + * Sort the given address list in RFC6724 order. + * Will leave the list unchanged if an error occurs. + * + * This function matches the behaviour of _rfc6724_sort in the native resolver. + */ + public static @NonNull List rfc6724Sort(@Nullable Network network, + @NonNull List answers) { + List sortableAnswerList = new ArrayList<>(); + answers.forEach(addr -> sortableAnswerList.add( + new SortableAddress(addr, findSrcAddress(network, addr)))); + + Collections.sort(sortableAnswerList, sRfc6724Comparator); + + final List sortedAnswers = new ArrayList<>(); + sortableAnswerList.forEach(ans -> sortedAnswers.add(ans.address)); + + return sortedAnswers; + } + + private static @Nullable InetAddress findSrcAddress(@Nullable Network network, + @NonNull InetAddress addr) { + final int domain; + if (isIpv4Address(addr)) { + domain = AF_INET; + } else if (isIpv6Address(addr)) { + domain = AF_INET6; + } else { + return null; + } + final FileDescriptor socket; + try { + socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP); + } catch (ErrnoException e) { + Log.e(TAG, "findSrcAddress:" + e.toString()); + return null; + } + try { + if (network != null) network.bindSocket(socket); + Os.connect(socket, new InetSocketAddress(addr, 0)); + return ((InetSocketAddress) Os.getsockname(socket)).getAddress(); + } catch (IOException | ErrnoException e) { + return null; + } finally { + IoUtils.closeQuietly(socket); + } + } + + /** + * Get the label for a given IPv4/IPv6 address. + * RFC 6724, section 2.1. + * + * Note that Java will return an IPv4-mapped address as an IPv4 address. + */ + private static int findLabel(@NonNull InetAddress addr) { + if (isIpv4Address(addr)) { + return 4; + } else if (isIpv6Address(addr)) { + if (addr.isLoopbackAddress()) { + return 0; + } else if (isIpv6Address6To4(addr)) { + return 2; + } else if (isIpv6AddressTeredo(addr)) { + return 5; + } else if (isIpv6AddressULA(addr)) { + return 13; + } else if (((Inet6Address) addr).isIPv4CompatibleAddress()) { + return 3; + } else if (addr.isSiteLocalAddress()) { + return 11; + } else if (isIpv6Address6Bone(addr)) { + return 12; + } else { + // All other IPv6 addresses, including global unicast addresses. + return 1; + } + } else { + // This should never happen. + return 1; + } + } + + private static boolean isIpv6Address(@Nullable InetAddress addr) { + return addr instanceof Inet6Address; + } + + private static boolean isIpv4Address(@Nullable InetAddress addr) { + return addr instanceof Inet4Address; + } + + private static boolean isIpv6Address6To4(@NonNull InetAddress addr) { + if (!isIpv6Address(addr)) return false; + final byte[] byteAddr = addr.getAddress(); + return byteAddr[0] == 0x20 && byteAddr[1] == 0x02; + } + + private static boolean isIpv6AddressTeredo(@NonNull InetAddress addr) { + if (!isIpv6Address(addr)) return false; + final byte[] byteAddr = addr.getAddress(); + return byteAddr[0] == 0x20 && byteAddr[1] == 0x01 && byteAddr[2] == 0x00 + && byteAddr[3] == 0x00; + } + + private static boolean isIpv6AddressULA(@NonNull InetAddress addr) { + return isIpv6Address(addr) && (addr.getAddress()[0] & 0xfe) == 0xfc; + } + + private static boolean isIpv6Address6Bone(@NonNull InetAddress addr) { + if (!isIpv6Address(addr)) return false; + final byte[] byteAddr = addr.getAddress(); + return byteAddr[0] == 0x3f && byteAddr[1] == (byte) 0xfe; + } + + private static int getIpv6MulticastScope(@NonNull InetAddress addr) { + return !isIpv6Address(addr) ? 0 : (addr.getAddress()[1] & 0x0f); + } + + private static int findScope(@NonNull InetAddress addr) { + if (isIpv6Address(addr)) { + if (addr.isMulticastAddress()) { + return getIpv6MulticastScope(addr); + } else if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) { + /** + * RFC 4291 section 2.5.3 says loopback is to be treated as having + * link-local scope. + */ + return IPV6_ADDR_SCOPE_LINKLOCAL; + } else if (addr.isSiteLocalAddress()) { + return IPV6_ADDR_SCOPE_SITELOCAL; + } else { + return IPV6_ADDR_SCOPE_GLOBAL; + } + } else if (isIpv4Address(addr)) { + if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) { + return IPV6_ADDR_SCOPE_LINKLOCAL; + } else { + /** + * RFC 6724 section 3.2. Other IPv4 addresses, including private addresses + * and shared addresses (100.64.0.0/10), are assigned global scope. + */ + return IPV6_ADDR_SCOPE_GLOBAL; + } + } else { + /** + * This should never happen. + * Return a scope with low priority as a last resort. + */ + return IPV6_ADDR_SCOPE_NODELOCAL; + } + } + + /** + * Get the precedence for a given IPv4/IPv6 address. + * RFC 6724, section 2.1. + * + * Note that Java will return an IPv4-mapped address as an IPv4 address. + */ + private static int findPrecedence(@NonNull InetAddress addr) { + if (isIpv4Address(addr)) { + return 35; + } else if (isIpv6Address(addr)) { + if (addr.isLoopbackAddress()) { + return 50; + } else if (isIpv6Address6To4(addr)) { + return 30; + } else if (isIpv6AddressTeredo(addr)) { + return 5; + } else if (isIpv6AddressULA(addr)) { + return 3; + } else if (((Inet6Address) addr).isIPv4CompatibleAddress() || addr.isSiteLocalAddress() + || isIpv6Address6Bone(addr)) { + return 1; + } else { + // All other IPv6 addresses, including global unicast addresses. + return 40; + } + } else { + return 1; + } + } + + /** + * Find number of matching initial bits between the two addresses. + */ + private static int compareIpv6PrefixMatchLen(@NonNull InetAddress srcAddr, + @NonNull InetAddress dstAddr) { + final byte[] srcByte = srcAddr.getAddress(); + final byte[] dstByte = dstAddr.getAddress(); + + // This should never happen. + if (srcByte.length != dstByte.length) return 0; + + for (int i = 0; i < dstByte.length; ++i) { + if (srcByte[i] == dstByte[i]) { + continue; + } + int x = BitUtils.uint8(srcByte[i]) ^ BitUtils.uint8(dstByte[i]); + return i * CHAR_BIT + (Integer.numberOfLeadingZeros(x) - 24); // Java ints are 32 bits + } + return dstByte.length * CHAR_BIT; + } + + /** + * Check if given network has Ipv4 capability + * This function matches the behaviour of have_ipv4 in the native resolver. + */ + public static boolean haveIpv4(@Nullable Network network) { + final SocketAddress addrIpv4 = + new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0); + return checkConnectivity(network, AF_INET, addrIpv4); + } + + /** + * Check if given network has Ipv6 capability + * This function matches the behaviour of have_ipv6 in the native resolver. + */ + public static boolean haveIpv6(@Nullable Network network) { + final SocketAddress addrIpv6 = + new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0); + return checkConnectivity(network, AF_INET6, addrIpv6); + } + + private static boolean checkConnectivity(@Nullable Network network, + int domain, @NonNull SocketAddress addr) { + final FileDescriptor socket; + try { + socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP); + } catch (ErrnoException e) { + return false; + } + try { + if (network != null) network.bindSocket(socket); + Os.connect(socket, addr); + } catch (IOException | ErrnoException e) { + return false; + } finally { + IoUtils.closeQuietly(socket); + } + return true; + } +} diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index c5fc9b3628..00e0e3a74d 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -18,26 +18,27 @@ #include -#include "jni.h" -#include -#include -#include "NetdClient.h" -#include -#include -#include #include -#include #include #include #include +#include #include #include #include #include #include -#include +#include +#include +#include +#include +#include +#include + +#include "NetdClient.h" #include "core_jni_helpers.h" +#include "jni.h" extern "C" { int ifc_enable(const char *ifname); @@ -303,6 +304,15 @@ static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobjec jniSetFileDescriptorOfFD(env, javaFd, -1); } +static jint android_net_utils_getDnsNetId(JNIEnv *env, jobject thiz) { + int dnsNetId = getNetworkForDns(); + if (dnsNetId < 0) { + throwErrnoException(env, "getDnsNetId", -dnsNetId); + } + + return dnsNetId; +} + static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) { if (javaFd == NULL) { jniThrowNullPointerException(env, NULL); @@ -359,6 +369,7 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery }, { "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult }, { "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel }, + { "getDnsNetId", "()I", (void*) android_net_utils_getDnsNetId }, }; int register_android_net_NetworkUtils(JNIEnv* env) diff --git a/tests/net/java/android/net/util/DnsUtilsTest.java b/tests/net/java/android/net/util/DnsUtilsTest.java new file mode 100644 index 0000000000..e5cb09f237 --- /dev/null +++ b/tests/net/java/android/net/util/DnsUtilsTest.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2019 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.util; + +import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_GLOBAL; +import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_LINKLOCAL; +import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_SITELOCAL; +import static android.net.util.DnsUtils.rfc6724Sort; + +import static org.junit.Assert.assertEquals; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.InetAddresses; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.InetAddress; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DnsUtilsTest { + private InetAddress stringToAddress(@NonNull String addr) { + return InetAddresses.parseNumericAddress(addr); + } + + private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr) { + return makeSortableAddress(addr, null); + } + + private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr, + @Nullable String srcAddr) { + return new DnsUtils.SortableAddress(stringToAddress(addr), + srcAddr != null ? stringToAddress(srcAddr) : null); + } + + @Test + public void testRfc6724Sort() { + final List testAddresses = Arrays.asList( + stringToAddress("172.217.24.14"), + stringToAddress("216.58.200.46"), + stringToAddress("2404:6800:4008:802::200e")); + + final List expected = Arrays.asList( + stringToAddress("2404:6800:4008:802::200e"), + stringToAddress("172.217.24.14"), + stringToAddress("216.58.200.46")); + + final List result = rfc6724Sort(null, testAddresses); + + assertEquals(result.size(), testAddresses.size()); + assertEquals(result, expected); + } + + @Test + public void testRfc6724Comparator() { + final List test = Arrays.asList( + makeSortableAddress("216.58.200.36"), // Ipv4 + makeSortableAddress("2404:6800:4008:801::2004"), // global + makeSortableAddress("::1"), // loop back + makeSortableAddress("fe80::c46f:1cff:fe04:39b4"), // link local + makeSortableAddress("::ffff:192.168.95.3"), // IPv4-mapped IPv6 + makeSortableAddress("2001::47c1"), // teredo tunneling + makeSortableAddress("::216.58.200.36"), // IPv4-compatible + makeSortableAddress("3ffe::1234:5678")); // 6bone + + final List expected = Arrays.asList( + stringToAddress("::1"), // loop back + stringToAddress("fe80::c46f:1cff:fe04:39b4"), // link local + stringToAddress("2404:6800:4008:801::2004"), // global + stringToAddress("216.58.200.36"), // Ipv4 + stringToAddress("::ffff:192.168.95.3"), // IPv4-mapped IPv6 + stringToAddress("2001::47c1"), // teredo tunneling + stringToAddress("::216.58.200.36"), // IPv4-compatible + stringToAddress("3ffe::1234:5678")); // 6bone + + Collections.sort(test, new DnsUtils.Rfc6724Comparator()); + + for (int i = 0; i < test.size(); ++i) { + assertEquals(test.get(i).address, expected.get(i)); + } + + // TODO: add more combinations + } + + @Test + public void testV4SortableAddress() { + // Test V4 address + DnsUtils.SortableAddress test = makeSortableAddress("216.58.200.36"); + assertEquals(test.hasSrcAddr, 0); + assertEquals(test.prefixMatchLen, 0); + assertEquals(test.address, stringToAddress("216.58.200.36")); + assertEquals(test.labelMatch, 0); + assertEquals(test.scopeMatch, 0); + assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL); + assertEquals(test.label, 4); + assertEquals(test.precedence, 35); + + // Test V4 loopback address with the same source address + test = makeSortableAddress("127.1.2.3", "127.1.2.3"); + assertEquals(test.hasSrcAddr, 1); + assertEquals(test.prefixMatchLen, 0); + assertEquals(test.address, stringToAddress("127.1.2.3")); + assertEquals(test.labelMatch, 1); + assertEquals(test.scopeMatch, 1); + assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL); + assertEquals(test.label, 4); + assertEquals(test.precedence, 35); + } + + @Test + public void testV6SortableAddress() { + // Test global address + DnsUtils.SortableAddress test = makeSortableAddress("2404:6800:4008:801::2004"); + assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004")); + assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL); + assertEquals(test.label, 1); + assertEquals(test.precedence, 40); + + // Test global address with global source address + test = makeSortableAddress("2404:6800:4008:801::2004", + "2401:fa00:fc:fd00:6d6c:7199:b8e7:41d6"); + assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004")); + assertEquals(test.hasSrcAddr, 1); + assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL); + assertEquals(test.labelMatch, 1); + assertEquals(test.scopeMatch, 1); + assertEquals(test.label, 1); + assertEquals(test.precedence, 40); + assertEquals(test.prefixMatchLen, 13); + + // Test global address with linklocal source address + test = makeSortableAddress("2404:6800:4008:801::2004", "fe80::c46f:1cff:fe04:39b4"); + assertEquals(test.hasSrcAddr, 1); + assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL); + assertEquals(test.labelMatch, 1); + assertEquals(test.scopeMatch, 0); + assertEquals(test.label, 1); + assertEquals(test.precedence, 40); + assertEquals(test.prefixMatchLen, 0); + + // Test loopback address with the same source address + test = makeSortableAddress("::1", "::1"); + assertEquals(test.hasSrcAddr, 1); + assertEquals(test.prefixMatchLen, 16 * 8); + assertEquals(test.labelMatch, 1); + assertEquals(test.scopeMatch, 1); + assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL); + assertEquals(test.label, 0); + assertEquals(test.precedence, 50); + + // Test linklocal address + test = makeSortableAddress("fe80::c46f:1cff:fe04:39b4"); + assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL); + assertEquals(test.label, 1); + assertEquals(test.precedence, 40); + + // Test linklocal address + test = makeSortableAddress("fe80::"); + assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL); + assertEquals(test.label, 1); + assertEquals(test.precedence, 40); + + // Test 6to4 address + test = makeSortableAddress("2002:c000:0204::"); + assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL); + assertEquals(test.label, 2); + assertEquals(test.precedence, 30); + + // Test unique local address + test = makeSortableAddress("fc00::c000:13ab"); + assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL); + assertEquals(test.label, 13); + assertEquals(test.precedence, 3); + + // Test teredo tunneling address + test = makeSortableAddress("2001::47c1"); + assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL); + assertEquals(test.label, 5); + assertEquals(test.precedence, 5); + + // Test IPv4-compatible addresses + test = makeSortableAddress("::216.58.200.36"); + assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL); + assertEquals(test.label, 3); + assertEquals(test.precedence, 1); + + // Test site-local address + test = makeSortableAddress("fec0::cafe:3ab2"); + assertEquals(test.scope, IPV6_ADDR_SCOPE_SITELOCAL); + assertEquals(test.label, 11); + assertEquals(test.precedence, 1); + + // Test 6bone address + test = makeSortableAddress("3ffe::1234:5678"); + assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL); + assertEquals(test.label, 12); + assertEquals(test.precedence, 1); + } +} From 0da57a8b67f848dcd5ef3857b7c7ab17d587077f Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Wed, 22 May 2019 09:17:33 -0700 Subject: [PATCH 091/130] [CM] Fix NPE due to unvalidated callback value When unregistering callback due to ON_UNAVAILABLE did not check for a non-null callback. Bug: 132950880 Test: atest ConnectivityServiceTest Merged-In: Ib3fde31d88c36469cdee1e3578606d130a9817cb Change-Id: Ib3fde31d88c36469cdee1e3578606d130a9817cb (cherry picked from commit 51ddc176abd23bd3ddbc26124e5541a983a1db07) --- .../java/android/net/ConnectivityManager.java | 9 +++-- .../server/ConnectivityServiceTest.java | 38 ++++++++++++++----- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3bc40a7999..fbfbfc04d8 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -3449,6 +3449,11 @@ public class ConnectivityManager { final NetworkCallback callback; synchronized (sCallbacks) { callback = sCallbacks.get(request); + if (callback == null) { + Log.w(TAG, + "callback not found for " + getCallbackName(message.what) + " message"); + return; + } if (message.what == CALLBACK_UNAVAIL) { sCallbacks.remove(request); callback.networkRequest = ALREADY_UNREGISTERED; @@ -3457,10 +3462,6 @@ public class ConnectivityManager { if (DBG) { Log.d(TAG, getCallbackName(message.what) + " for network " + network); } - if (callback == null) { - Log.w(TAG, "callback not found for " + getCallbackName(message.what) + " message"); - return; - } switch (message.what) { case CALLBACK_PRECHECK: { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index b0cc20785c..03af9672c1 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -3816,11 +3816,20 @@ public class ConnectivityServiceTest { networkCallback.assertNoCallback(); } + @Test + public void testUnfulfillableNetworkRequest() throws Exception { + runUnfulfillableNetworkRequest(false); + } + + @Test + public void testUnfulfillableNetworkRequestAfterUnregister() throws Exception { + runUnfulfillableNetworkRequest(true); + } + /** * Validate the callback flow for a factory releasing a request as unfulfillable. */ - @Test - public void testUnfulfillableNetworkRequest() throws Exception { + private void runUnfulfillableNetworkRequest(boolean preUnregister) throws Exception { NetworkRequest nr = new NetworkRequest.Builder().addTransportType( NetworkCapabilities.TRANSPORT_WIFI).build(); final TestNetworkCallback networkCallback = new TestNetworkCallback(); @@ -3855,14 +3864,25 @@ public class ConnectivityServiceTest { } } - // Simulate the factory releasing the request as unfulfillable and expect onUnavailable! - testFactory.expectRemoveRequests(1); - testFactory.triggerUnfulfillable(requests.get(newRequestId)); - networkCallback.expectCallback(CallbackState.UNAVAILABLE, null); - testFactory.waitForRequests(); + if (preUnregister) { + mCm.unregisterNetworkCallback(networkCallback); - // unregister network callback - a no-op, but should not fail - mCm.unregisterNetworkCallback(networkCallback); + // Simulate the factory releasing the request as unfulfillable: no-op since + // the callback has already been unregistered (but a test that no exceptions are + // thrown). + testFactory.triggerUnfulfillable(requests.get(newRequestId)); + } else { + // Simulate the factory releasing the request as unfulfillable and expect onUnavailable! + testFactory.expectRemoveRequests(1); + testFactory.triggerUnfulfillable(requests.get(newRequestId)); + + networkCallback.expectCallback(CallbackState.UNAVAILABLE, null); + testFactory.waitForRequests(); + + // unregister network callback - a no-op (since already freed by the + // on-unavailable), but should not fail or throw exceptions. + mCm.unregisterNetworkCallback(networkCallback); + } testFactory.unregister(); handlerThread.quit(); From c8289e40a4c837e40fc402bada475f2319e179eb Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Thu, 23 May 2019 09:16:26 -0700 Subject: [PATCH 092/130] [CM] Fix NPE due to unvalidated callback value Fix flaky test resulting from the above fix. Bug: 132950880 Test: atest ConnectivityServiceTest Merged-In: Ia2cc04b42288ea987483e5ab0e0a10093dc49502 Change-Id: Ia2cc04b42288ea987483e5ab0e0a10093dc49502 (cherry picked from commit cc65a628eb1172dc7b942d7f51b702099c15c23b) --- tests/net/java/com/android/server/ConnectivityServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 03af9672c1..fa059fa9e8 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -3864,6 +3864,7 @@ public class ConnectivityServiceTest { } } + testFactory.expectRemoveRequests(1); if (preUnregister) { mCm.unregisterNetworkCallback(networkCallback); @@ -3873,7 +3874,6 @@ public class ConnectivityServiceTest { testFactory.triggerUnfulfillable(requests.get(newRequestId)); } else { // Simulate the factory releasing the request as unfulfillable and expect onUnavailable! - testFactory.expectRemoveRequests(1); testFactory.triggerUnfulfillable(requests.get(newRequestId)); networkCallback.expectCallback(CallbackState.UNAVAILABLE, null); From 158ac5a39e4098042d9b1957e1835ae30237683d Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Wed, 22 May 2019 15:28:49 -0700 Subject: [PATCH 093/130] Fix the internet permission for native services The native services should specify their permissions in platform.xml if they need internet permission, otherwise the eBPF program will block the socket creation request. Fixing the known services that are in group AID_INET but didn't specify their permission in the xml file. Bug: 132217906 Test: CtsJdwpTestCases dumpsys netd trafficcontroller Change-Id: I84cde7d3757953bc0bf761727d64a715bcdd68bb Merged-In: I84cde7d3757953bc0bf761727d64a715bcdd68bb (cherry picked from commit e5d6f0fa6c3fd77572f5b29f416acbf304abf9da) --- .../android/server/connectivity/PermissionMonitor.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index d05369e9cf..fbe2589bea 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -199,15 +199,13 @@ public class PermissionMonitor { ArraySet perms = systemPermission.valueAt(i); int uid = systemPermission.keyAt(i); int netdPermission = 0; - // Get the uids of native services that have UPDATE_DEVICE_STATS permission. + // Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission. if (perms != null) { netdPermission |= perms.contains(UPDATE_DEVICE_STATS) ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0; + netdPermission |= perms.contains(INTERNET) + ? INetd.PERMISSION_INTERNET : 0; } - // For internet permission, the native services have their own selinux domains and - // sepolicy will control the socket creation during run time. netd cannot block the - // socket creation based on the permission information here. - netdPermission |= INetd.PERMISSION_INTERNET; netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission); } log("Users: " + mUsers.size() + ", Apps: " + mApps.size()); From dc07f26256cd8696176eb3ca736b54f51f50c11b Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 23 May 2019 22:57:18 -0700 Subject: [PATCH 094/130] Update multiple validation result to ConnectivityService Once a network is determined to have partial connectivity, it cannot go back to full connectivity without a disconnect. This is because NetworkMonitor can only communicate either PARTIAL_CONNECTIVITY or VALID, but not both. Thus, multiple validation results allow ConnectivityService to know the real network status. Bug: 129662877 Bug: 130683832 Test: atest FrameworksNetTests Test: atest NetworkStackTests Test: atest --generate-new-metrics 50 NetworkStackTests:com.android.server.connectivity.NetworkMonitorTest Test: Simulate partial connectvitiy Change-Id: I406c9368617c03a2dd3ab15fb1f6dbf539d7c714 Merged-In: I243db4c406cca826e803c8035268bc0c6e6e01e2 (cherry picked from commit 4532abd4d2af9ad118873a63cafc6028ed87c52e) --- .../android/server/ConnectivityService.java | 32 ++++--- .../server/ConnectivityServiceTest.java | 84 +++++++++++++++++-- 2 files changed, 89 insertions(+), 27 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f12bfc33ea..181668122f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -25,8 +25,8 @@ import static android.net.ConnectivityManager.TYPE_NONE; import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; -import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY; -import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID; +import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL; +import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID; 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; @@ -2605,21 +2605,12 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2); if (nai == null) break; - final boolean partialConnectivity = - (msg.arg1 == NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY) - || (nai.networkMisc.acceptPartialConnectivity - && nai.partialConnectivity); - // Once a network is determined to have partial connectivity, it cannot - // go back to full connectivity without a disconnect. This is because - // NetworkMonitor can only communicate either PARTIAL_CONNECTIVITY or VALID, - // but not both. - // TODO: Provide multi-testResult to improve the communication between - // ConnectivityService and NetworkMonitor, so that ConnectivityService could - // know the real status of network. + final boolean wasPartial = nai.partialConnectivity; + nai.partialConnectivity = ((msg.arg1 & NETWORK_VALIDATION_RESULT_PARTIAL) != 0); final boolean partialConnectivityChanged = - (partialConnectivity && !nai.partialConnectivity); + (wasPartial != nai.partialConnectivity); - final boolean valid = (msg.arg1 == NETWORK_TEST_RESULT_VALID); + final boolean valid = ((msg.arg1 & NETWORK_VALIDATION_RESULT_VALID) != 0); final boolean wasValidated = nai.lastValidated; final boolean wasDefault = isDefaultNetwork(nai); if (nai.everCaptivePortalDetected && !nai.captivePortalLoginNotified @@ -2649,21 +2640,23 @@ public class ConnectivityService extends IConnectivityManager.Stub if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai); if (valid) { handleFreshlyValidatedNetwork(nai); - // Clear NO_INTERNET and LOST_INTERNET notifications if network becomes - // valid. + // Clear NO_INTERNET, PARTIAL_CONNECTIVITY and LOST_INTERNET + // notifications if network becomes valid. mNotifier.clearNotification(nai.network.netId, NotificationType.NO_INTERNET); mNotifier.clearNotification(nai.network.netId, NotificationType.LOST_INTERNET); + mNotifier.clearNotification(nai.network.netId, + NotificationType.PARTIAL_CONNECTIVITY); } } else if (partialConnectivityChanged) { - nai.partialConnectivity = partialConnectivity; updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities); } updateInetCondition(nai); // Let the NetworkAgent know the state of its network Bundle redirectUrlBundle = new Bundle(); redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl); + // TODO: Evaluate to update partial connectivity to status to NetworkAgent. nai.asyncChannel.sendMessage( NetworkAgent.CMD_REPORT_NETWORK_STATUS, (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), @@ -3443,6 +3436,9 @@ public class ConnectivityService extends IConnectivityManager.Stub // Inform NetworkMonitor that partial connectivity is acceptable. This will likely // result in a partial connectivity result which will be processed by // maybeHandleNetworkMonitorMessage. + // + // TODO: NetworkMonitor does not refer to the "never ask again" bit. The bit is stored + // per network. Therefore, NetworkMonitor may still do https probe. try { nai.networkMonitor().setAcceptPartialConnectivity(); } catch (RemoteException e) { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index fa059fa9e8..6560f58cde 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -30,9 +30,12 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; import static android.net.ConnectivityManager.TYPE_NONE; import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID; -import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY; -import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID; +import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS; +import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK; +import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP; +import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS; +import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL; +import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID; import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; @@ -443,6 +446,16 @@ public class ConnectivityServiceTest { } private class MockNetworkAgent { + private static final int VALIDATION_RESULT_BASE = NETWORK_VALIDATION_PROBE_DNS + | NETWORK_VALIDATION_PROBE_HTTP + | NETWORK_VALIDATION_PROBE_HTTPS; + private static final int VALIDATION_RESULT_VALID = VALIDATION_RESULT_BASE + | NETWORK_VALIDATION_RESULT_VALID; + private static final int VALIDATION_RESULT_PARTIAL = VALIDATION_RESULT_BASE + | NETWORK_VALIDATION_PROBE_FALLBACK + | NETWORK_VALIDATION_RESULT_PARTIAL; + private static final int VALIDATION_RESULT_INVALID = 0; + private final INetworkMonitor mNetworkMonitor; private final NetworkInfo mNetworkInfo; private final NetworkCapabilities mNetworkCapabilities; @@ -460,17 +473,17 @@ public class ConnectivityServiceTest { private String mRedirectUrl; private INetworkMonitorCallbacks mNmCallbacks; - private int mNmValidationResult = NETWORK_TEST_RESULT_INVALID; + private int mNmValidationResult = VALIDATION_RESULT_BASE; private String mNmValidationRedirectUrl = null; private boolean mNmProvNotificationRequested = false; void setNetworkValid() { - mNmValidationResult = NETWORK_TEST_RESULT_VALID; + mNmValidationResult = VALIDATION_RESULT_VALID; mNmValidationRedirectUrl = null; } void setNetworkInvalid() { - mNmValidationResult = NETWORK_TEST_RESULT_INVALID; + mNmValidationResult = VALIDATION_RESULT_INVALID; mNmValidationRedirectUrl = null; } @@ -480,7 +493,12 @@ public class ConnectivityServiceTest { } void setNetworkPartial() { - mNmValidationResult = NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY; + mNmValidationResult = VALIDATION_RESULT_PARTIAL; + mNmValidationRedirectUrl = null; + } + + void setNetworkPartialValid() { + mNmValidationResult = VALIDATION_RESULT_PARTIAL | VALIDATION_RESULT_VALID; mNmValidationRedirectUrl = null; } @@ -597,7 +615,7 @@ public class ConnectivityServiceTest { private void onValidationRequested() { try { if (mNmProvNotificationRequested - && mNmValidationResult == NETWORK_TEST_RESULT_VALID) { + && mNmValidationResult == VALIDATION_RESULT_VALID) { mNmCallbacks.hideProvisioningNotification(); mNmProvNotificationRequested = false; } @@ -2651,7 +2669,7 @@ public class ConnectivityServiceTest { // With HTTPS probe disabled, NetworkMonitor should pass the network validation with http // probe. - mWiFiNetworkAgent.setNetworkValid(); + mWiFiNetworkAgent.setNetworkPartialValid(); // If the user chooses yes to use this partial connectivity wifi, switch the default // network to wifi and check if wifi becomes valid or not. mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */, @@ -2748,6 +2766,54 @@ public class ConnectivityServiceTest { callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); } + @Test + public void testCaptivePortalOnPartialConnectivity() throws RemoteException { + final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); + final NetworkRequest captivePortalRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build(); + mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback); + + final TestNetworkCallback validatedCallback = new TestNetworkCallback(); + final NetworkRequest validatedRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_VALIDATED).build(); + mCm.registerNetworkCallback(validatedRequest, validatedCallback); + + // Bring up a network with a captive portal. + // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + String firstRedirectUrl = "http://example.com/firstPath"; + mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl); + + // Check that startCaptivePortalApp sends the expected command to NetworkMonitor. + mCm.startCaptivePortalApp(mWiFiNetworkAgent.getNetwork()); + verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1)) + .launchCaptivePortalApp(); + + // Report that the captive portal is dismissed with partial connectivity, and check that + // callbacks are fired. + mWiFiNetworkAgent.setNetworkPartial(); + mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); + waitForIdle(); + captivePortalCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, + mWiFiNetworkAgent); + + // Report partial connectivity is accepted. + mWiFiNetworkAgent.setNetworkPartialValid(); + mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */, + false /* always */); + waitForIdle(); + mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); + validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); + NetworkCapabilities nc = + validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, + mWiFiNetworkAgent); + + mCm.unregisterNetworkCallback(captivePortalCallback); + mCm.unregisterNetworkCallback(validatedCallback); + } + @Test public void testCaptivePortal() { final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); From 1be379bbb425cc92d819777a2364bd99769e6661 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Sat, 25 May 2019 08:42:17 -0700 Subject: [PATCH 095/130] Clean up for multiple validation result update This is a follow-up commit for aosp/955431 to update commets and minor updates in unit test. Test: atest com.android.server.ConnectivityServiceTest#testCaptivePortalOnPartialConnectivity Bug: 130683832 Change-Id: I581eae8daeddd2c4c186e7b40e27fef2aaa7ab43 Merged-In: I9087ef791b3fee5399ba8e83ef9d8a544845a4dd Merged-In: I4424663292c5ad29eb7a888fa6975835721a5d2e (cherry picked from commit 3d3a9fff7b7fa0df4ee627cb082668e642d6f754) --- .../com/android/server/ConnectivityServiceTest.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 6560f58cde..8c024a5a53 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -615,7 +615,7 @@ public class ConnectivityServiceTest { private void onValidationRequested() { try { if (mNmProvNotificationRequested - && mNmValidationResult == VALIDATION_RESULT_VALID) { + && ((mNmValidationResult & NETWORK_VALIDATION_RESULT_VALID) != 0)) { mNmCallbacks.hideProvisioningNotification(); mNmProvNotificationRequested = false; } @@ -2781,10 +2781,10 @@ public class ConnectivityServiceTest { // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - String firstRedirectUrl = "http://example.com/firstPath"; - mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl); + String redirectUrl = "http://android.com/path"; + mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl); captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); - assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl); + assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), redirectUrl); // Check that startCaptivePortalApp sends the expected command to NetworkMonitor. mCm.startCaptivePortalApp(mWiFiNetworkAgent.getNetwork()); @@ -2794,7 +2794,7 @@ public class ConnectivityServiceTest { // Report that the captive portal is dismissed with partial connectivity, and check that // callbacks are fired. mWiFiNetworkAgent.setNetworkPartial(); - mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); + mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); waitForIdle(); captivePortalCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent); @@ -2805,6 +2805,7 @@ public class ConnectivityServiceTest { false /* always */); waitForIdle(); mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true); + captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); NetworkCapabilities nc = validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, From ddfa1f5f4dddd9f7af3f2166a8d2722db19de45d Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 27 May 2019 04:33:13 -0700 Subject: [PATCH 096/130] Reinstate access to a forgotten member Followup to aosp/964440 Bug: 131764329 Test: none Merged-In: I6f6b2cf75793532d3d537a223b8e15d7304a1e3f Change-Id: Ib279c0076016c53e0491fc0df8cefff8ae280d66 (cherry picked from commit 41bd3c57b4ba347ac6eb4546855daf5473264a29) --- core/java/android/net/StaticIpConfiguration.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java index fe42111afb..050fcfa252 100644 --- a/core/java/android/net/StaticIpConfiguration.java +++ b/core/java/android/net/StaticIpConfiguration.java @@ -22,7 +22,6 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.net.shared.InetAddressUtils; -import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -54,7 +53,7 @@ import java.util.Objects; @TestApi public final class StaticIpConfiguration implements Parcelable { /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @UnsupportedAppUsage @Nullable public LinkAddress ipAddress; /** @hide */ From 4aa400f7eb26fae776abaac66385858474e3b771 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Mon, 27 May 2019 11:19:15 -0700 Subject: [PATCH 097/130] Remove broken test testRfc6724Sort This test is conitnuely fail in cuttlefish. Lack of ipv6 default route in cuttlefish caused the test failed. The reason is that the result of rfc6724Sort depends on on the route in system. It is not good to expect any route should exists, so remove it. Bug: 133649648 Test: atest DnsUtilsTest Merged-In: Idc6db433585de067e45088b43665c8e37b310397 (cherry picked from commit 91b35f88429d77ddce0e3f539690e6370b89915b) Change-Id: Idb6f4c094d3466772e3bfc98a57505bf38f381ef --- .../java/android/net/util/DnsUtilsTest.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/tests/net/java/android/net/util/DnsUtilsTest.java b/tests/net/java/android/net/util/DnsUtilsTest.java index e5cb09f237..42e340bbcb 100644 --- a/tests/net/java/android/net/util/DnsUtilsTest.java +++ b/tests/net/java/android/net/util/DnsUtilsTest.java @@ -19,7 +19,6 @@ package android.net.util; import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_GLOBAL; import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_LINKLOCAL; import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_SITELOCAL; -import static android.net.util.DnsUtils.rfc6724Sort; import static org.junit.Assert.assertEquals; @@ -55,24 +54,6 @@ public class DnsUtilsTest { srcAddr != null ? stringToAddress(srcAddr) : null); } - @Test - public void testRfc6724Sort() { - final List testAddresses = Arrays.asList( - stringToAddress("172.217.24.14"), - stringToAddress("216.58.200.46"), - stringToAddress("2404:6800:4008:802::200e")); - - final List expected = Arrays.asList( - stringToAddress("2404:6800:4008:802::200e"), - stringToAddress("172.217.24.14"), - stringToAddress("216.58.200.46")); - - final List result = rfc6724Sort(null, testAddresses); - - assertEquals(result.size(), testAddresses.size()); - assertEquals(result, expected); - } - @Test public void testRfc6724Comparator() { final List test = Arrays.asList( From fbb2a4935c7c1f6c7b3c4332e1dbbb30f5c58cd1 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Mon, 27 May 2019 18:22:55 -0700 Subject: [PATCH 098/130] Wipe the data in IpMemoryStore database upon network factory reset. Bug:128499160 Test: manual Test: atest FrameworksNetTests NetworkStackTests Merged-In: I13ad04454e638905b74dd42a1c83266c7c37652f Merged-In: Ia13ff10a57c2043f6676976f23ecfb2d2a9a6ef0 (cherry picked from commit ef6ef68c48b869aa9960edd81c73f3d31391ae26) Change-Id: I42507451d55a620c0e2d271c895ad158f348c1a5 --- .../core/java/com/android/server/ConnectivityService.java | 4 ++++ tests/net/java/android/net/IpMemoryStoreTest.java | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 181668122f..0a1dbff38b 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -77,6 +77,7 @@ import android.net.INetworkStatsService; import android.net.ISocketKeepaliveCallback; import android.net.ITetheringEventCallback; import android.net.InetAddresses; +import android.net.IpMemoryStore; import android.net.IpPrefix; import android.net.LinkProperties; import android.net.LinkProperties.CompareResult; @@ -6888,6 +6889,9 @@ public class ConnectivityService extends IConnectivityManager.Stub final int userId = UserHandle.getCallingUserId(); + final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext); + ipMemoryStore.factoryReset(); + // Turn airplane mode off setAirplaneMode(false); diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java index 6e69b34fe4..b81ca36429 100644 --- a/tests/net/java/android/net/IpMemoryStoreTest.java +++ b/tests/net/java/android/net/IpMemoryStoreTest.java @@ -321,4 +321,11 @@ public class IpMemoryStoreTest { eq(TEST_OTHER_DATA_NAME), any()); assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue())); } + + @Test + public void testFactoryReset() throws RemoteException { + startIpMemoryStore(true /* supplyService */); + mStore.factoryReset(); + verify(mMockService, times(1)).factoryReset(); + } } From 805327de42d3d833404ffd918501743a05244add Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 28 May 2019 06:01:54 -0700 Subject: [PATCH 099/130] Let the system server have CONNECTIVITY_USE_RESTRICTED_NETWORKS. Also : - Fix testUidFilteringDuringVpnConnectDisconnectAndUidUpdates that was failing on devices with a first released SDK >= Q - Add a test actually tests that the system has the permission, as the test was only testing what's in the mock Bug: 119770201 Test: New test making sure this stays true Merged-In: I74cf5f0fa17fcf818f1fed78c7e3e4375c20152e Change-Id: I0daa644fbad8e389ad7cfa66c0e3b3480c8bb50a (cherry picked from commit 629b49d58fe8d108a3d7d47a21471aff913c6b34) --- .../connectivity/PermissionMonitorTest.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index df1f57f7a0..cd2bd26ef4 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -65,6 +65,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.SparseIntArray; +import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -96,6 +97,7 @@ public class PermissionMonitorTest { private static final int SYSTEM_UID1 = 1000; private static final int SYSTEM_UID2 = 1008; private static final int VPN_UID = 10002; + private static final String REAL_SYSTEM_PACKAGE_NAME = "android"; private static final String MOCK_PACKAGE1 = "appName1"; private static final String MOCK_PACKAGE2 = "appName2"; private static final String SYSTEM_PACKAGE1 = "sysName1"; @@ -188,8 +190,10 @@ public class PermissionMonitorTest { private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) { final PackageInfo pkgInfo; if (hasSystemPermission) { - pkgInfo = packageInfoWithPermissions(new String[] {CHANGE_NETWORK_STATE, NETWORK_STACK}, - PARTITION_SYSTEM); + final String[] systemPermissions = new String[]{ + CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS + }; + pkgInfo = packageInfoWithPermissions(systemPermissions, PARTITION_SYSTEM); } else { pkgInfo = packageInfoWithPermissions(new String[] {}, ""); } @@ -646,4 +650,16 @@ public class PermissionMonitorTest { mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); } + + @Test + public void testRealSystemPermission() throws Exception { + // Use the real context as this test must ensure the *real* system package holds the + // necessary permission. + final Context realContext = InstrumentationRegistry.getContext(); + final PermissionMonitor monitor = new PermissionMonitor(realContext, mNetdService); + final PackageManager manager = realContext.getPackageManager(); + final PackageInfo systemInfo = manager.getPackageInfo(REAL_SYSTEM_PACKAGE_NAME, + GET_PERMISSIONS | MATCH_ANY_USER); + assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); + } } From 97482de1fd3824be733c11a9e0a2c1ad0a2eb702 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Sun, 17 Feb 2019 23:43:25 -0800 Subject: [PATCH 100/130] Take all VPN underlying networks into account when migrating traffic for VPN uid. (cherry picked from commit 612520f5448b6d46c05ca60fb99c8d45433a9474) Bug: 113122541 Bug: 120145746 Test: atest FrameworksNetTests Test: Manually verified on device that stats from VPN UID are moved appropriately based on its declared underlying network set. Test: vogar --mode app_process --benchmark NetworkStatsBenchmark.java Change-Id: I7f368c5970b2dcb969fe0daf5ef44edb1f51d09d --- .../android/server/ConnectivityService.java | 27 ++-- .../java/android/net/NetworkStatsTest.java | 4 +- .../server/net/NetworkStatsServiceTest.java | 142 +++++++++++++++++- 3 files changed, 154 insertions(+), 19 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f12bfc33ea..c20f01fcf5 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4366,7 +4366,7 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * @return VPN information for accounting, or null if we can't retrieve all required - * information, e.g primary underlying iface. + * information, e.g underlying ifaces. */ @Nullable private VpnInfo createVpnInfo(Vpn vpn) { @@ -4378,17 +4378,24 @@ public class ConnectivityService extends IConnectivityManager.Stub // see VpnService.setUnderlyingNetworks()'s javadoc about how to interpret // the underlyingNetworks list. if (underlyingNetworks == null) { - NetworkAgentInfo defaultNetwork = getDefaultNetwork(); - if (defaultNetwork != null && defaultNetwork.linkProperties != null) { - info.primaryUnderlyingIface = getDefaultNetwork().linkProperties.getInterfaceName(); - } - } else if (underlyingNetworks.length > 0) { - LinkProperties linkProperties = getLinkProperties(underlyingNetworks[0]); - if (linkProperties != null) { - info.primaryUnderlyingIface = linkProperties.getInterfaceName(); + NetworkAgentInfo defaultNai = getDefaultNetwork(); + if (defaultNai != null && defaultNai.linkProperties != null) { + underlyingNetworks = new Network[] { defaultNai.network }; } } - return info.primaryUnderlyingIface == null ? null : info; + if (underlyingNetworks != null && underlyingNetworks.length > 0) { + List interfaces = new ArrayList<>(); + for (Network network : underlyingNetworks) { + LinkProperties lp = getLinkProperties(network); + if (lp != null) { + interfaces.add(lp.getInterfaceName()); + } + } + if (!interfaces.isEmpty()) { + info.underlyingIfaces = interfaces.toArray(new String[interfaces.size()]); + } + } + return info.underlyingIfaces == null ? null : info; } /** diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index b5b0384ca5..9ed6cb9b45 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -569,7 +569,7 @@ public class NetworkStatsTest { .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L); - assertTrue(delta.toString(), delta.migrateTun(tunUid, tunIface, underlyingIface)); + delta.migrateTun(tunUid, tunIface, new String[] {underlyingIface}); assertEquals(20, delta.size()); // tunIface and TEST_IFACE entries are not changed. @@ -650,7 +650,7 @@ public class NetworkStatsTest { .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L); - assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface)); + delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface}); assertEquals(9, delta.size()); // tunIface entries should not be changed. diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index bce526d3ae..c46534c8d0 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -927,7 +927,7 @@ public class NetworkStatsServiceTest { // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). expectDefaultSettings(); NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()}; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)}; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); @@ -947,8 +947,10 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L) .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L) - .addValues( - TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 1650L, 150L, 2L)); + // VPN received 1650 bytes over WiFi in background (SET_DEFAULT). + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 0L, 0L, 1L) + // VPN sent 1650 bytes over WiFi in foreground (SET_FOREGROUND). + .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 1650L, 150L, 1L)); forcePollAndWaitForIdle(); @@ -962,7 +964,7 @@ public class NetworkStatsServiceTest { // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). expectDefaultSettings(); NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()}; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)}; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); @@ -992,6 +994,132 @@ public class NetworkStatsServiceTest { assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0); } + @Test + public void vpnWithTwoUnderlyingIfaces_packetDuplication() throws Exception { + // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and + // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set. + // Additionally, VPN is duplicating traffic across both WiFi and Cell. + expectDefaultSettings(); + NetworkState[] networkStates = + new NetworkState[] { + buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState() + }; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})}; + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces( + new Network[] {WIFI_NETWORK, VPN_NETWORK}, + vpnInfos, + networkStates, + getActiveIface(networkStates)); + // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption + // overhead per packet): + // 1000 bytes (100 packets) were sent/received by UID_RED and UID_BLUE over VPN. + // VPN sent/received 4400 bytes (400 packets) over both WiFi and Cell (8800 bytes in total). + // Of 8800 bytes over WiFi/Cell, expect: + // - 500 bytes rx/tx each over WiFi/Cell attributed to both UID_RED and UID_BLUE. + // - 1200 bytes rx/tx each over WiFi/Cell for VPN_UID. + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 4) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L) + .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L) + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 2200L, 200L, 2200L, 200L, 2L) + .addValues( + TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 2200L, 200L, 2200L, 200L, 2L)); + + forcePollAndWaitForIdle(); + + assertUidTotal(sTemplateWifi, UID_RED, 500L, 50L, 500L, 50L, 1); + assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1); + assertUidTotal(sTemplateWifi, UID_VPN, 1200L, 100L, 1200L, 100L, 2); + + assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 500L, 50L, 500L, 50L, 1); + assertUidTotal(buildTemplateMobileWildcard(), UID_BLUE, 500L, 50L, 500L, 50L, 1); + assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1200L, 100L, 1200L, 100L, 2); + } + + @Test + public void vpnWithTwoUnderlyingIfaces_splitTraffic() throws Exception { + // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and + // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set. + // Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell. + expectDefaultSettings(); + NetworkState[] networkStates = + new NetworkState[] { + buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState() + }; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})}; + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces( + new Network[] {WIFI_NETWORK, VPN_NETWORK}, + vpnInfos, + networkStates, + getActiveIface(networkStates)); + // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption + // overhead per packet): + // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. + // VPN sent/received 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell. + // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for both + // rx/tx. + // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for both rx/tx. + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L) + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 660L, 60L, 660L, 60L, 1L) + .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 440L, 40L, 440L, 40L, 1L)); + + forcePollAndWaitForIdle(); + + assertUidTotal(sTemplateWifi, UID_RED, 600L, 60L, 600L, 60L, 1); + assertUidTotal(sTemplateWifi, UID_VPN, 60L, 0L, 60L, 0L, 1); + + assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 400L, 40L, 400L, 40L, 1); + assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 40L, 0L, 40L, 0L, 1); + } + + @Test + public void vpnWithTwoUnderlyingIfaces_splitTrafficWithCompression() throws Exception { + // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and + // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set. + // Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell. + expectDefaultSettings(); + NetworkState[] networkStates = + new NetworkState[] { + buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState() + }; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})}; + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces( + new Network[] {WIFI_NETWORK, VPN_NETWORK}, + vpnInfos, + networkStates, + getActiveIface(networkStates)); + // create some traffic (assume 10 bytes of MTU for VPN interface: + // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. + // VPN sent/received 600 bytes (60 packets) over WiFi and 200 bytes (20 packets) over Cell. + // For UID_RED, expect 600 bytes attributed over WiFi and 200 bytes over Cell for both + // rx/tx. + // UID_VPN gets nothing attributed to it (avoiding negative stats). + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 4) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L) + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 600L, 60L, 600L, 60L, 0L) + .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 200L, 20L, 200L, 20L, 0L)); + + forcePollAndWaitForIdle(); + + assertUidTotal(sTemplateWifi, UID_RED, 600L, 60L, 600L, 60L, 0); + assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0); + + assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 200L, 20L, 200L, 20L, 0); + assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 0L, 0L, 0L, 0L, 0); + } + @Test public void vpnWithIncorrectUnderlyingIface() throws Exception { // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2), @@ -1001,7 +1129,7 @@ public class NetworkStatsServiceTest { new NetworkState[] { buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState() }; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)}; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); @@ -1382,11 +1510,11 @@ public class NetworkStatsServiceTest { return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null); } - private static VpnInfo createVpnInfo(String underlyingIface) { + private static VpnInfo createVpnInfo(String[] underlyingIfaces) { VpnInfo info = new VpnInfo(); info.ownerUid = UID_VPN; info.vpnIface = TUN_IFACE; - info.primaryUnderlyingIface = underlyingIface; + info.underlyingIfaces = underlyingIfaces; return info; } From e7094673d53330ce501d3ccb946a91ded1ba7ccb Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Fri, 18 Jan 2019 19:22:48 -0800 Subject: [PATCH 101/130] NetworkStatsService: Fix getDetailedUidStats to take VPNs into account. (cherry picked from commit 2af0b66aba89a4d1eeed69823967b659628f271c) This API is similar to one provided by NetworkStatsFactory with the difference that NSS also migrates traffic from VPN UID to other apps. Since traffic can only be migrated over NetworkStats delta, NSS therefore maintains NetworkStats snapshot across all UIDs/ifaces/tags. This snapshot gets updated whenever NSS records a new snapshot (based on various hooks such as VPN updating its underlying networks, network getting lost, etc.), or getDetailedUidStats API is invoked by one of its callers. Bug: 113122541 Bug: 120145746 Test: atest FrameworksNetTests Test: manually verified that battery stats are migrating traffic off of TUN (after patching above CL where we point BatteryStats to use this API). Change-Id: I4b8d7c5b6905a4a12c1806dfd35c2c4c63610404 --- .../java/android/net/NetworkStatsTest.java | 31 ++++ .../server/net/NetworkStatsServiceTest.java | 148 +++++++++++++++++- 2 files changed, 173 insertions(+), 6 deletions(-) diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index 9ed6cb9b45..c16a0f4466 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -812,6 +812,37 @@ public class NetworkStatsTest { assertEquals(entry2, stats.getValues(1, null)); } + @Test + public void testFilterDebugEntries() { + NetworkStats.Entry entry1 = new NetworkStats.Entry( + "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "test2", 10101, SET_DBG_VPN_IN, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry3 = new NetworkStats.Entry( + "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry4 = new NetworkStats.Entry( + "test2", 10101, SET_DBG_VPN_OUT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 4) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3) + .addValues(entry4); + + stats.filterDebugEntries(); + + assertEquals(2, stats.size()); + assertEquals(entry1, stats.getValues(0, null)); + assertEquals(entry3, stats.getValues(1, null)); + } + @Test public void testApply464xlatAdjustments() { final String v4Iface = "v4-wlan0"; diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index c46534c8d0..e35c34affd 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -57,6 +57,7 @@ import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_PO import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -216,11 +217,16 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectSystemReady(); + assertNull(mService.getTunAdjustedStats()); mService.systemReady(); + // Verify that system ready fetches realtime stats and initializes tun adjusted stats. + verify(mNetManager).getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL); + assertNotNull("failed to initialize TUN adjusted stats", mService.getTunAdjustedStats()); + assertEquals(0, mService.getTunAdjustedStats().size()); + mSession = mService.openSession(); assertNotNull("openSession() failed", mSession); - // catch INetworkManagementEventObserver during systemReady() ArgumentCaptor networkObserver = ArgumentCaptor.forClass(INetworkManagementEventObserver.class); @@ -733,11 +739,13 @@ public class NetworkStatsServiceTest { NetworkStats stats = mService.getDetailedUidStats(ifaceFilter); - verify(mNetManager, times(1)).getNetworkStatsUidDetail(eq(UID_ALL), argThat(ifaces -> - ifaces != null && ifaces.length == 2 - && ArrayUtils.contains(ifaces, TEST_IFACE) - && ArrayUtils.contains(ifaces, stackedIface))); - + // mNetManager#getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL) has following invocations: + // 1) NetworkStatsService#systemReady from #setUp. + // 2) mService#forceUpdateIfaces in the test above. + // 3) Finally, mService#getDetailedUidStats. + verify(mNetManager, times(3)).getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL); + assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), TEST_IFACE)); + assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), stackedIface)); assertEquals(2, stats.size()); assertEquals(uidStats, stats.getValues(0, null)); assertEquals(tetheredStats1, stats.getValues(1, null)); @@ -1157,6 +1165,134 @@ public class NetworkStatsServiceTest { assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1100L, 100L, 1100L, 100L, 1); } + @Test + public void recordSnapshot_migratesTunTrafficAndUpdatesTunAdjustedStats() throws Exception { + assertEquals(0, mService.getTunAdjustedStats().size()); + // VPN using WiFi (TEST_IFACE). + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; + expectBandwidthControlCheck(); + // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption + // overhead per packet): + // 1000 bytes (100 packets) were downloaded by UID_RED over VPN. + // VPN received 1100 bytes (100 packets) over WiFi. + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L) + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L)); + + // this should lead to NSS#recordSnapshotLocked + mService.forceUpdateIfaces( + new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */); + + // Verify TUN adjusted stats have traffic migrated correctly. + // Of 1100 bytes VPN received over WiFi, expect 1000 bytes attributed to UID_RED and 100 + // bytes attributed to UID_VPN. + NetworkStats tunAdjStats = mService.getTunAdjustedStats(); + assertValues( + tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0); + assertValues( + tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0); + } + + @Test + public void getDetailedUidStats_migratesTunTrafficAndUpdatesTunAdjustedStats() + throws Exception { + assertEquals(0, mService.getTunAdjustedStats().size()); + // VPN using WiFi (TEST_IFACE). + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; + expectBandwidthControlCheck(); + mService.forceUpdateIfaces( + new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */); + // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption + // overhead per packet): + // 1000 bytes (100 packets) were downloaded by UID_RED over VPN. + // VPN received 1100 bytes (100 packets) over WiFi. + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L) + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L)); + + mService.getDetailedUidStats(INTERFACES_ALL); + + // Verify internally maintained TUN adjusted stats + NetworkStats tunAdjStats = mService.getTunAdjustedStats(); + // Verify stats for TEST_IFACE (WiFi): + // Of 1100 bytes VPN received over WiFi, expect 1000 bytes attributed to UID_RED and 100 + // bytes attributed to UID_VPN. + assertValues( + tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0); + assertValues( + tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0); + // Verify stats for TUN_IFACE; only UID_RED should have usage on it. + assertValues( + tunAdjStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0); + assertValues( + tunAdjStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 0L, 0L, 0L, 0L, 0); + + // lets assume that since last time, VPN received another 1100 bytes (same assumptions as + // before i.e. UID_RED downloaded another 1000 bytes). + incrementCurrentTime(HOUR_IN_MILLIS); + // Note - NetworkStatsFactory returns counters that are monotonically increasing. + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 0L, 0L, 0L) + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 2200L, 200L, 0L, 0L, 0L)); + + mService.getDetailedUidStats(INTERFACES_ALL); + + tunAdjStats = mService.getTunAdjustedStats(); + // verify TEST_IFACE stats: + assertValues( + tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 2000L, 200L, 0L, 0L, 0); + assertValues( + tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 200L, 0L, 0L, 0L, 0); + // verify TUN_IFACE stats: + assertValues( + tunAdjStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 2000L, 200L, 0L, 0L, 0); + assertValues( + tunAdjStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 0L, 0L, 0L, 0L, 0); + } + + @Test + public void getDetailedUidStats_returnsCorrectStatsWithVpnRunning() throws Exception { + // VPN using WiFi (TEST_IFACE). + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; + expectBandwidthControlCheck(); + mService.forceUpdateIfaces( + new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */); + // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption + // overhead per packet): + // 1000 bytes (100 packets) were downloaded by UID_RED over VPN. + // VPN received 1100 bytes (100 packets) over WiFi. + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L) + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L)); + + // Query realtime stats for TEST_IFACE. + NetworkStats queriedStats = + mService.getDetailedUidStats(new String[] {TEST_IFACE}); + + assertEquals(HOUR_IN_MILLIS, queriedStats.getElapsedRealtime()); + // verify that returned stats are only for TEST_IFACE and VPN traffic is migrated correctly. + assertEquals(new String[] {TEST_IFACE}, queriedStats.getUniqueIfaces()); + assertValues( + queriedStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0); + assertValues( + queriedStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0); + } + @Test public void testRegisterUsageCallback() throws Exception { // pretend that wifi network comes online; service should ask about full From 78d5ac4f8f5dfbd0b771f1ade8b28914074d5a2a Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Fri, 24 May 2019 16:29:22 -0700 Subject: [PATCH 102/130] Addressing comments for http://ag/7700679. Note, that its in a separate CL so we could cherry-pick this CL to aosp. http://ag/7700679 is already in aosp. Bug: 113122541 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: I7cfda226b4ed11b67002b83b38fba0f5caf96718 --- .../android/server/ConnectivityService.java | 4 +- .../server/net/NetworkStatsServiceTest.java | 115 ++++++++++++++---- 2 files changed, 93 insertions(+), 26 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index c20f01fcf5..bf65c2949b 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4379,7 +4379,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // the underlyingNetworks list. if (underlyingNetworks == null) { NetworkAgentInfo defaultNai = getDefaultNetwork(); - if (defaultNai != null && defaultNai.linkProperties != null) { + if (defaultNai != null) { underlyingNetworks = new Network[] { defaultNai.network }; } } @@ -4387,7 +4387,7 @@ public class ConnectivityService extends IConnectivityManager.Stub List interfaces = new ArrayList<>(); for (Network network : underlyingNetworks) { LinkProperties lp = getLinkProperties(network); - if (lp != null) { + if (lp != null && !TextUtils.isEmpty(lp.getInterfaceName())) { interfaces.add(lp.getInterfaceName()); } } diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index e35c34affd..66a267665e 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -930,6 +930,65 @@ public class NetworkStatsServiceTest { assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0); } + @Test + public void vpnRewriteTrafficThroughItself() throws Exception { + // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). + expectDefaultSettings(); + NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()}; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces( + new Network[] {WIFI_NETWORK, VPN_NETWORK}, + vpnInfos, + networkStates, + getActiveIface(networkStates)); + // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption + // overhead per packet): + // + // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED + // over VPN. + // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE + // over VPN. + // + // VPN UID rewrites packets read from TUN back to TUN, plus some of its own traffic + // (100 bytes). + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 5) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 1000L, 100L, 1L) + .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 500L, 50L, 1L) + // VPN rewrites all the packets read from TUN + 100 additional bytes of VPN's + // own traffic. + .addValues(TUN_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 0L, 0L, 1600L, 160L, 2L) + // VPN sent 1760 bytes over WiFi in foreground (SET_FOREGROUND) i.e. 1600 + // bytes (160 packets) + 1 byte/packet overhead (=160 bytes). + .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 1760L, 176L, 1L) + // VPN received 3300 bytes over WiFi in background (SET_DEFAULT) i.e. 3000 bytes + // (300 packets) + 1 byte/packet encryption overhead (=300 bytes). + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 3300L, 300L, 0L, 0L, 1L)); + + forcePollAndWaitForIdle(); + + // Verify increased TUN usage by UID_VPN does not get attributed to other apps. + NetworkStats tunStats = + mService.getDetailedUidStats(new String[] {TUN_IFACE}); + assertValues( + tunStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 2000L, 200L, 1000L, 100L, 1); + assertValues( + tunStats, TUN_IFACE, UID_BLUE, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 1000L, 100L, 500L, 50L, 1); + assertValues( + tunStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, 0L, 0L, 1600L, 160L, 2); + + // Verify correct attribution over WiFi. + assertUidTotal(sTemplateWifi, UID_RED, 2000L, 200L, 1000L, 100L, 1); + assertUidTotal(sTemplateWifi, UID_BLUE, 1000L, 100L, 500L, 50L, 1); + assertUidTotal(sTemplateWifi, UID_VPN, 300L, 0L, 260L, 26L, 2); + } + @Test public void vpnWithOneUnderlyingIface() throws Exception { // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). @@ -946,25 +1005,29 @@ public class NetworkStatsServiceTest { getActiveIface(networkStates)); // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption // overhead per packet): - // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. - // 500 bytes (50 packets) were sent/received by UID_BLUE over VPN. - // VPN sent/received 1650 bytes (150 packets) over WiFi. - // Of 1650 bytes over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes attributed to - // UID_BLUE, and 150 bytes attributed to UID_VPN for both rx/tx traffic. + // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED + // over VPN. + // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE + // over VPN. + // VPN sent 1650 bytes (150 packets), and received 3300 (300 packets) over WiFi. + // Of 1650 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes + // attributed to UID_BLUE, and 150 bytes attributed to UID_VPN. + // Of 3300 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes + // attributed to UID_BLUE, and 300 bytes attributed to UID_VPN. incrementCurrentTime(HOUR_IN_MILLIS); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L) - .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L) - // VPN received 1650 bytes over WiFi in background (SET_DEFAULT). - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 0L, 0L, 1L) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 1000L, 100L, 1L) + .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 500L, 50L, 1L) + // VPN received 3300 bytes over WiFi in background (SET_DEFAULT). + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 3300L, 300L, 0L, 0L, 1L) // VPN sent 1650 bytes over WiFi in foreground (SET_FOREGROUND). .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 1650L, 150L, 1L)); forcePollAndWaitForIdle(); - assertUidTotal(sTemplateWifi, UID_RED, 1000L, 100L, 1000L, 100L, 1); - assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1); - assertUidTotal(sTemplateWifi, UID_VPN, 150L, 0L, 150L, 0L, 2); + assertUidTotal(sTemplateWifi, UID_RED, 2000L, 200L, 1000L, 100L, 1); + assertUidTotal(sTemplateWifi, UID_BLUE, 1000L, 100L, 500L, 50L, 1); + assertUidTotal(sTemplateWifi, UID_VPN, 300L, 0L, 150L, 0L, 2); } @Test @@ -1068,24 +1131,28 @@ public class NetworkStatsServiceTest { getActiveIface(networkStates)); // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption // overhead per packet): - // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. - // VPN sent/received 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell. - // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for both - // rx/tx. - // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for both rx/tx. + // 1000 bytes (100 packets) were sent, and 500 bytes (50 packets) received by UID_RED over + // VPN. + // VPN sent 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell. + // And, it received 330 bytes (30 packets) over WiFi and 220 bytes (20 packets) over Cell. + // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for sent (tx) + // traffic. For received (rx) traffic, expect 300 bytes over WiFi and 200 bytes over Cell. + // + // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for tx traffic. + // And, 30 bytes over WiFi and 20 bytes over Cell for rx traffic. incrementCurrentTime(HOUR_IN_MILLIS); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L) - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 660L, 60L, 660L, 60L, 1L) - .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 440L, 40L, 440L, 40L, 1L)); + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 500L, 50L, 1000L, 100L, 2L) + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 330L, 30L, 660L, 60L, 1L) + .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 220L, 20L, 440L, 40L, 1L)); forcePollAndWaitForIdle(); - assertUidTotal(sTemplateWifi, UID_RED, 600L, 60L, 600L, 60L, 1); - assertUidTotal(sTemplateWifi, UID_VPN, 60L, 0L, 60L, 0L, 1); + assertUidTotal(sTemplateWifi, UID_RED, 300L, 30L, 600L, 60L, 1); + assertUidTotal(sTemplateWifi, UID_VPN, 30L, 0L, 60L, 0L, 1); - assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 400L, 40L, 400L, 40L, 1); - assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 40L, 0L, 40L, 0L, 1); + assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 200L, 20L, 400L, 40L, 1); + assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 20L, 0L, 40L, 0L, 1); } @Test From 20204cdf6a2a41408e036d87993241f66362a2d0 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 29 May 2019 19:02:41 +0900 Subject: [PATCH 103/130] Add one more test for VPN usage stats. Covers the case where the majority of traffic through the VPN is caused by the VPN app itself, and ensures that that traffic is correctly attributed to the VPN app as opposed to spread between the other apps that use the VPN. Bug: 120145746 Test: atest NetworkStatsServiceTest Change-Id: Iffd3f95fc2e11d311691a797b010edb38d2ef3c6 --- .../server/net/NetworkStatsServiceTest.java | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 66a267665e..d9f2c201fe 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -62,7 +62,6 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -1030,6 +1029,51 @@ public class NetworkStatsServiceTest { assertUidTotal(sTemplateWifi, UID_VPN, 300L, 0L, 150L, 0L, 2); } + @Test + public void vpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception { + // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). + expectDefaultSettings(); + NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()}; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces( + new Network[] {WIFI_NETWORK, VPN_NETWORK}, + vpnInfos, + networkStates, + getActiveIface(networkStates)); + // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption + // overhead per packet): + // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED + // over VPN. + // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE + // over VPN. + // Additionally, the VPN sends 6000 bytes (600 packets) of its own traffic into the tun + // interface (passing that traffic to the VPN endpoint), and receives 5000 bytes (500 + // packets) from it. Including overhead that is 6600/5500 bytes. + // VPN sent 8250 bytes (750 packets), and received 8800 (800 packets) over WiFi. + // Of 8250 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes + // attributed to UID_BLUE, and 6750 bytes attributed to UID_VPN. + // Of 8800 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes + // attributed to UID_BLUE, and 5800 bytes attributed to UID_VPN. + incrementCurrentTime(HOUR_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 1000L, 100L, 1L) + .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 500L, 50L, 1L) + .addValues(TUN_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 5000L, 500L, 6000L, 600L, 1L) + // VPN received 8800 bytes over WiFi in background (SET_DEFAULT). + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 8800L, 800L, 0L, 0L, 1L) + // VPN sent 8250 bytes over WiFi in foreground (SET_FOREGROUND). + .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 8250L, 750L, 1L)); + + forcePollAndWaitForIdle(); + + assertUidTotal(sTemplateWifi, UID_RED, 2000L, 200L, 1000L, 100L, 1); + assertUidTotal(sTemplateWifi, UID_BLUE, 1000L, 100L, 500L, 50L, 1); + assertUidTotal(sTemplateWifi, UID_VPN, 5800L, 500L, 6750L, 600L, 2); + } + @Test public void vpnWithOneUnderlyingIface_withCompression() throws Exception { // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). From 381513f5e105d288917fddee6868787e36cb72ac Mon Sep 17 00:00:00 2001 From: chen xu Date: Wed, 22 May 2019 14:10:29 -0700 Subject: [PATCH 104/130] NetworkStatAccess Should checkCarrierPrivileges cross all subscriptions Bug: 133236378 Test: Manual Change-Id: I49fbde1fe73b33aadcf8fd23ad224f363b137bf3 Merged-in: I49fbde1fe73b33aadcf8fd23ad224f363b137bf3 --- .../net/java/com/android/server/net/NetworkStatsAccessTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java index 6e725dd69c..858358c74f 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java @@ -161,7 +161,7 @@ public class NetworkStatsAccessTest { } private void setHasCarrierPrivileges(boolean hasPrivileges) { - when(mTm.checkCarrierPrivilegesForPackage(TEST_PKG)).thenReturn( + when(mTm.checkCarrierPrivilegesForPackageAnyPhone(TEST_PKG)).thenReturn( hasPrivileges ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS : TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS); } From 336e84677946076f51b21da6bb16c71755499ffc Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 30 May 2019 16:24:31 +0900 Subject: [PATCH 105/130] Don't auto-connect to networks that have no/limited connectivity. Auto-reconnecting to a network with no or limited Internet connectivity is not useful. This is because such networks cannot be used unless the user taps the notification and interacts with the resulting dialog. But the notification is only shown if the user manually connects to the network, not if the system auto-connects to it. Bug: 130683832 Bug: 130766237 Test: atest FrameworksNetTests Change-Id: I5413393529c4bad3a707df229307542486bcff33 --- .../core/java/com/android/server/ConnectivityService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 45f7360a25..a119ebe242 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3660,6 +3660,13 @@ public class ConnectivityService extends IConnectivityManager.Stub || nai.networkMisc.acceptPartialConnectivity) { return; } + + // Stop automatically reconnecting to this network in the future. Automatically connecting + // to a network that provides no or limited connectivity is not useful, because the user + // cannot use that network except through the notification shown by this method, and the + // notification is only shown if the network is explicitly selected by the user. + nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT); + // TODO: Evaluate if it's needed to wait 8 seconds for triggering notification when // NetworkMonitor detects the network is partial connectivity. Need to change the design to // popup the notification immediately when the network is partial connectivity. From 5c7c1def90d4ac6be20bf77653f1e513817616f2 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 30 May 2019 01:48:24 -0700 Subject: [PATCH 106/130] Always give VPN the INTERNET capability. Split-tunnel VPN (which are the only ones affected by this change) always fall through to the default network for routes they don't handle, and even if the underlying network(s) don't provide access this may be a pinhole that can actually reach the broader network. In practice this behaves like the original release of P and is the safest thing to do for Q. In R we should evaluate giving the VPN app the ability to simply tell the network stack whether it does provide Internet access or not. Bug: 119216095 Test: FrameworksNetTests NetworkStackTests Change-Id: I262ca41fe0225660551c9a421562405366b6acac Merged-In: I262ca41fe0225660551c9a421562405366b6acac (cherry picked from commit 6d5a4a3b1d1c69eb8a542fecf5e8a306822c19b7) --- .../android/server/connectivity/VpnTest.java | 90 ------------------- 1 file changed, 90 deletions(-) diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 2cae250902..ce50bef53d 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -727,94 +727,4 @@ public class VpnTest { "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6", "fe00::/8", "2605:ef80:e:af1d::/64"); } - - @Test - public void testProvidesRoutesToMostDestinations() { - final LinkProperties lp = new LinkProperties(); - - // Default route provides routes to all IPv4 destinations. - lp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"))); - assertTrue(Vpn.providesRoutesToMostDestinations(lp)); - - // Empty LP provides routes to no destination - lp.clear(); - assertFalse(Vpn.providesRoutesToMostDestinations(lp)); - - // All IPv4 routes except for local networks. This is the case most relevant - // to this function. It provides routes to almost the entire space. - // (clone the stream so that we can reuse it later) - publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s)))); - assertTrue(Vpn.providesRoutesToMostDestinations(lp)); - - // Removing a 16-bit prefix, which is 65536 addresses. This is still enough to - // provide routes to "most" destinations. - lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16"))); - assertTrue(Vpn.providesRoutesToMostDestinations(lp)); - - // Remove the /2 route, which represent a quarter of the available routing space. - // This LP does not provides routes to "most" destinations any more. - lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2"))); - assertFalse(Vpn.providesRoutesToMostDestinations(lp)); - - lp.clear(); - publicIpV6Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s)))); - assertTrue(Vpn.providesRoutesToMostDestinations(lp)); - - lp.removeRoute(new RouteInfo(new IpPrefix("::/1"))); - assertFalse(Vpn.providesRoutesToMostDestinations(lp)); - - // V6 does not provide sufficient coverage but v4 does - publicIpV4Routes().forEach(s -> lp.addRoute(new RouteInfo(new IpPrefix(s)))); - assertTrue(Vpn.providesRoutesToMostDestinations(lp)); - - // V4 still does - lp.removeRoute(new RouteInfo(new IpPrefix("192.169.0.0/16"))); - assertTrue(Vpn.providesRoutesToMostDestinations(lp)); - - // V4 does not any more - lp.removeRoute(new RouteInfo(new IpPrefix("64.0.0.0/2"))); - assertFalse(Vpn.providesRoutesToMostDestinations(lp)); - - // V4 does not, but V6 has sufficient coverage again - lp.addRoute(new RouteInfo(new IpPrefix("::/1"))); - assertTrue(Vpn.providesRoutesToMostDestinations(lp)); - - lp.clear(); - // V4-unreachable route should not be treated as sufficient coverage - lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE)); - assertFalse(Vpn.providesRoutesToMostDestinations(lp)); - - lp.clear(); - // V6-unreachable route should not be treated as sufficient coverage - lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); - assertFalse(Vpn.providesRoutesToMostDestinations(lp)); - } - - @Test - public void testDoesNotLockUpWithTooManyRoutes() { - final LinkProperties lp = new LinkProperties(); - final byte[] ad = new byte[4]; - // Actually evaluating this many routes under 1500ms is impossible on - // current hardware and for some time, as the algorithm is O(n²). - // Make sure the system has a safeguard against this and does not - // lock up. - final int MAX_ROUTES = 4000; - final long MAX_ALLOWED_TIME_MS = 1500; - for (int i = 0; i < MAX_ROUTES; ++i) { - ad[0] = (byte)((i >> 24) & 0xFF); - ad[1] = (byte)((i >> 16) & 0xFF); - ad[2] = (byte)((i >> 8) & 0xFF); - ad[3] = (byte)(i & 0xFF); - try { - lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.getByAddress(ad), 32))); - } catch (UnknownHostException e) { - // UnknownHostException is only thrown for an address of illegal length, - // which can't happen in the case above. - } - } - final long start = SystemClock.currentThreadTimeMillis(); - assertTrue(Vpn.providesRoutesToMostDestinations(lp)); - final long end = SystemClock.currentThreadTimeMillis(); - assertTrue(end - start < MAX_ALLOWED_TIME_MS); - } } From 551043d3e4c50a0018fa590234f4e185a8e1343d Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 30 May 2019 04:10:30 -0700 Subject: [PATCH 107/130] Replace limited connectivity notification after detecting it No internet notification may be prompted before partial connectivity being detected. Partial connectivity status will be set into NAI and prompted in the Setting. Behavior is not aligned between Setting and notification. Thus, update notification again if partial connectivity is detected. Also, sliently show the updated notification if no internet notification has already been shown to user to prevent alerting user in short time. Bug: 130683832 Test: Verified with simulated partial connectivity Test: atest FrameworksNetTests Change-Id: Ie16a8ce6e0fa437048e8c1eea240314ca30e9520 Merged-In: I004e78a33689e2208918d4316bcf9a8f50a0bac3 Merged-In: I14385a39d99a45c4a6a50a665f456f589c2f4da3 (cherry picked from commit a5c68348d89f256cb5f42283d983d05834c7e36c) --- .../connectivity/NetworkNotificationManager.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index 0910dac273..f6735d9834 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -237,9 +237,15 @@ public class NetworkNotificationManager { + getTransportName(transportType)); return; } - - final String channelId = highPriority ? SystemNotificationChannels.NETWORK_ALERTS : - SystemNotificationChannels.NETWORK_STATUS; + // When replacing an existing notification for a given network, don't alert, just silently + // update the existing notification. Note that setOnlyAlertOnce() will only work for the + // same id, and the id used here is the NotificationType which is different in every type of + // notification. This is required because the notification metrics only track the ID but not + // the tag. + final boolean hasPreviousNotification = previousNotifyType != null; + final String channelId = (highPriority && !hasPreviousNotification) + ? SystemNotificationChannels.NETWORK_ALERTS + : SystemNotificationChannels.NETWORK_STATUS; Notification.Builder builder = new Notification.Builder(mContext, channelId) .setWhen(System.currentTimeMillis()) .setShowWhen(notifyType == NotificationType.NETWORK_SWITCH) From 976e09ab5c06dc7b537069da1c46ceb9606d24c9 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Thu, 30 May 2019 04:46:40 -0700 Subject: [PATCH 108/130] Fix issue for DnsResolver#query 1. Previously, getDnsNetId doesn't handle all the cases. Fix it with cosidering bypass private DNS flag. 2. Make getDnsNetId return Network instead of netId, and change name from getDnsNetId to getDnsNetwork Bug: 129530368 Test: atest DnsResolverTest DnsUtilsTest Merged-In: Ibb5080acd3c296650d56532fc7da525e9fa95e8f (cherry picked from commit 3854966dc9499e39187835606397b16367e5e27b) Change-Id: I37353642088bcc17da0cf17f78a5ed9efc9aefc3 --- core/java/android/net/DnsResolver.java | 6 +++--- core/java/android/net/NetworkUtils.java | 5 ++--- core/jni/android_net_NetUtils.cpp | 18 ++++++++++++------ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java index 4b2b4c35b2..7a85dcbfc8 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -16,7 +16,7 @@ package android.net; -import static android.net.NetworkUtils.getDnsNetId; +import static android.net.NetworkUtils.getDnsNetwork; import static android.net.NetworkUtils.resNetworkCancel; import static android.net.NetworkUtils.resNetworkQuery; import static android.net.NetworkUtils.resNetworkResult; @@ -333,7 +333,7 @@ public final class DnsResolver { final Object lock = new Object(); final Network queryNetwork; try { - queryNetwork = (network != null) ? network : new Network(getDnsNetId()); + queryNetwork = (network != null) ? network : getDnsNetwork(); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -433,7 +433,7 @@ public final class DnsResolver { final FileDescriptor queryfd; final Network queryNetwork; try { - queryNetwork = (network != null) ? network : new Network(getDnsNetId()); + queryNetwork = (network != null) ? network : getDnsNetwork(); queryfd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, nsType, flags); } catch (ErrnoException e) { diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index a640f83ea5..d0f54b4c7f 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -158,10 +158,9 @@ public class NetworkUtils { /** * DNS resolver series jni method. - * Attempts to get netid of network which resolver will - * use if no network is explicitly selected. + * Attempts to get network which resolver will use if no network is explicitly selected. */ - public static native int getDnsNetId() throws ErrnoException; + public static native Network getDnsNetwork() throws ErrnoException; /** * Get the tcp repair window associated with the {@code fd}. diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 00e0e3a74d..08aa1d97fa 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -304,13 +304,19 @@ static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobjec jniSetFileDescriptorOfFD(env, javaFd, -1); } -static jint android_net_utils_getDnsNetId(JNIEnv *env, jobject thiz) { - int dnsNetId = getNetworkForDns(); - if (dnsNetId < 0) { - throwErrnoException(env, "getDnsNetId", -dnsNetId); +static jobject android_net_utils_getDnsNetwork(JNIEnv *env, jobject thiz) { + unsigned dnsNetId = 0; + if (int res = getNetworkForDns(&dnsNetId) < 0) { + throwErrnoException(env, "getDnsNetId", -res); + return nullptr; } + bool privateDnsBypass = dnsNetId & NETID_USE_LOCAL_NAMESERVERS; - return dnsNetId; + static jclass class_Network = MakeGlobalRefOrDie( + env, FindClassOrDie(env, "android/net/Network")); + static jmethodID ctor = env->GetMethodID(class_Network, "", "(IZ)V"); + return env->NewObject( + class_Network, ctor, dnsNetId & ~NETID_USE_LOCAL_NAMESERVERS, privateDnsBypass); } static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) { @@ -369,7 +375,7 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery }, { "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult }, { "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel }, - { "getDnsNetId", "()I", (void*) android_net_utils_getDnsNetId }, + { "getDnsNetwork", "()Landroid/net/Network;", (void*) android_net_utils_getDnsNetwork }, }; int register_android_net_NetworkUtils(JNIEnv* env) From ef64770162f19acc6e6d61e6dd57d43a5dfd4818 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 30 May 2019 03:50:19 -0700 Subject: [PATCH 109/130] Prevent a 4-way binder interlock leading to a leak. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit System server | NetworkStack | NetworkMonitorCallbacks ←----|--- NetworkMonitorCallbacks$Stub$Proxy ↓ | ↑ NetworkAgentInfo | NetworkMonitor ↓ | ↑ NetworkMonitor$Stub$Proxy ----|---→ NetworkMonitorImpl Bug: b/133174607 Test: Manual. The simplest artifact is observed by watching the output of adb shell dumpsys meminfo -d com.android.networkstack | grep 'Proxy Binders' while connecting and disconnecting multiple times to any network. This will display the number of binder proxies. Before this, the binder proxy count increases by 1 with each connection and never goes down (there is some noise, as proxy objects are sometimes created for other reasons, and get GC'd eventually). After this, the binder proxy count is always eventually stable at 27 + connected network count. See the bug for the complete analysis. Merged-In: Ide2428dab3fcd6d7cd00aa2a9fd99d6c99b815a4 Change-Id: I6b74cf12bdbc72c0593d2a4d6f39c895d1ef3534 (cherry picked from commit eb43884fee35102a7fc886750d6a7e891a82ce33) --- .../android/server/ConnectivityService.java | 19 +++++---- .../connectivity/AutodestructReference.java | 42 +++++++++++++++++++ 2 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 services/core/java/com/android/server/connectivity/AutodestructReference.java diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 45f7360a25..863389b85d 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -169,6 +169,7 @@ import com.android.internal.util.MessageUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; +import com.android.server.connectivity.AutodestructReference; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; @@ -2763,29 +2764,31 @@ public class ConnectivityService extends IConnectivityManager.Stub } private class NetworkMonitorCallbacks extends INetworkMonitorCallbacks.Stub { - private final NetworkAgentInfo mNai; + private final int mNetId; + private final AutodestructReference mNai; private NetworkMonitorCallbacks(NetworkAgentInfo nai) { - mNai = nai; + mNetId = nai.network.netId; + mNai = new AutodestructReference(nai); } @Override public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) { mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, - new Pair<>(mNai, networkMonitor))); + new Pair<>(mNai.getAndDestroy(), networkMonitor))); } @Override public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) { mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(EVENT_NETWORK_TESTED, - testResult, mNai.network.netId, redirectUrl)); + testResult, mNetId, redirectUrl)); } @Override public void notifyPrivateDnsConfigResolved(PrivateDnsConfigParcel config) { mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage( EVENT_PRIVATE_DNS_CONFIG_RESOLVED, - 0, mNai.network.netId, PrivateDnsConfig.fromParcel(config))); + 0, mNetId, PrivateDnsConfig.fromParcel(config))); } @Override @@ -2803,15 +2806,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage( EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_SHOW, - mNai.network.netId, - pendingIntent)); + mNetId, pendingIntent)); } @Override public void hideProvisioningNotification() { mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage( - EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE, - mNai.network.netId)); + EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE, mNetId)); } @Override diff --git a/services/core/java/com/android/server/connectivity/AutodestructReference.java b/services/core/java/com/android/server/connectivity/AutodestructReference.java new file mode 100644 index 0000000000..009a43e582 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/AutodestructReference.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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.connectivity; + +import android.annotation.NonNull; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * A ref that autodestructs at the first usage of it. + * @param The type of the held object + * @hide + */ +public class AutodestructReference { + private final AtomicReference mHeld; + public AutodestructReference(@NonNull T obj) { + if (null == obj) throw new NullPointerException("Autodestruct reference to null"); + mHeld = new AtomicReference<>(obj); + } + + /** Get the ref and destruct it. NPE if already destructed. */ + @NonNull + public T getAndDestroy() { + final T obj = mHeld.getAndSet(null); + if (null == obj) throw new NullPointerException("Already autodestructed"); + return obj; + } +} From 7577c856bcb5975666b313f51c5dfac02e5b2095 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 31 May 2019 07:17:35 -0700 Subject: [PATCH 110/130] Don't crash ConnectivityService if the network stack crashes. When the network stack crashes, the system will rebind to it. Existing references are no longer useful (they just throw RemoteException) but if the system is still up, then the user can at least recover the situation by taking actions such as going into airplane mode, toggling wifi, etc. This CL stops ConnectivityService from crashing the system when it cannot talk to NetworkMonitor. This is arguably better than crashing the system, because crashing the system is disruptive and carries the serious risk of a bootloop from which it is not possible to recover. NetworkStackClient already contains code to crash the system when the network stack crashes. This change help ensure that if a crash occurs, it is the result of an explicit decision by that code instead of an unchecked exception in one of the callers of the network stack. Bug: 133725814 Test: builds, boots Test: atest FrameworksNetTests NetworkStackTests Change-Id: Ib9a15fececd8579fc5b139fe0341275a45512e0f Merged-In: Ib9a15fececd8579fc5b139fe0341275a45512e0f (cherry picked from commit ac29a97d10fe8ea0720763f4ca4657cac85732a1) --- .../android/server/ConnectivityService.java | 65 +++++-------------- .../server/connectivity/NetworkAgentInfo.java | 18 ++--- 2 files changed, 22 insertions(+), 61 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 863389b85d..d6b4043af4 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -91,6 +91,7 @@ import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; +import android.net.NetworkMonitorManager; import android.net.NetworkPolicyManager; import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; @@ -1786,8 +1787,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // caller type. Need to re-factor NetdEventListenerService to allow multiple // NetworkMonitor registrants. if (nai != null && nai.satisfies(mDefaultRequest)) { - Binder.withCleanCallingIdentity(() -> - nai.networkMonitor().notifyDnsResponse(returnCode)); + nai.networkMonitor().notifyDnsResponse(returnCode); } } @@ -2854,11 +2854,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Notify the NetworkAgentInfo/NetworkMonitor in case NetworkMonitor needs to cancel or // schedule DNS resolutions. If a DNS resolution is required the // result will be sent back to us. - try { - nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel()); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } + nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel()); // With Private DNS bypass support, we can proceed to update the // Private DNS config immediately, even if we're in strict mode @@ -3024,11 +3020,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Disable wakeup packet monitoring for each interface. wakeupModifyInterface(iface, nai.networkCapabilities, false); } - try { - nai.networkMonitor().notifyNetworkDisconnected(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } + nai.networkMonitor().notifyNetworkDisconnected(); mNetworkAgentInfos.remove(nai.messenger); nai.clatd.update(); synchronized (mNetworkForNetId) { @@ -3441,11 +3433,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // // TODO: NetworkMonitor does not refer to the "never ask again" bit. The bit is stored // per network. Therefore, NetworkMonitor may still do https probe. - try { - nai.networkMonitor().setAcceptPartialConnectivity(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } + nai.networkMonitor().setAcceptPartialConnectivity(); } } @@ -3477,11 +3465,7 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); if (nai == null) return; if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return; - try { - nai.networkMonitor().launchCaptivePortalApp(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } + nai.networkMonitor().launchCaptivePortalApp(); }); } @@ -3516,7 +3500,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public void appResponse(final int response) throws RemoteException { + public void appResponse(final int response) { if (response == CaptivePortal.APP_RETURN_WANTED_AS_IS) { enforceSettingsPermission(); } @@ -3526,16 +3510,9 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nai == null) return; // nai.networkMonitor() is thread-safe - final INetworkMonitor nm = nai.networkMonitor(); + final NetworkMonitorManager nm = nai.networkMonitor(); if (nm == null) return; - - final long token = Binder.clearCallingIdentity(); - try { - nm.notifyCaptivePortalAppFinished(response); - } finally { - // Not using Binder.withCleanCallingIdentity() to keep the checked RemoteException - Binder.restoreCallingIdentity(token); - } + nm.notifyCaptivePortalAppFinished(response); } @Override @@ -4106,11 +4083,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (isNetworkWithLinkPropertiesBlocked(lp, uid, false)) { return; } - try { - nai.networkMonitor().forceReevaluation(uid); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } + nai.networkMonitor().forceReevaluation(uid); } /** @@ -5543,11 +5516,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Start or stop DNS64 detection and 464xlat according to network state. networkAgent.clatd.update(); notifyIfacesChangedForNetworkStats(); - try { - networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } + networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp); if (networkAgent.everConnected) { notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED); } @@ -6531,15 +6500,11 @@ public class ConnectivityService extends IConnectivityManager.Stub // command must be sent after updating LinkProperties to maximize chances of // NetworkMonitor seeing the correct LinkProperties when starting. // TODO: pass LinkProperties to the NetworkMonitor in the notifyNetworkConnected call. - try { - if (networkAgent.networkMisc.acceptPartialConnectivity) { - networkAgent.networkMonitor().setAcceptPartialConnectivity(); - } - networkAgent.networkMonitor().notifyNetworkConnected( - networkAgent.linkProperties, networkAgent.networkCapabilities); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); + if (networkAgent.networkMisc.acceptPartialConnectivity) { + networkAgent.networkMonitor().setAcceptPartialConnectivity(); } + networkAgent.networkMonitor().notifyNetworkConnected( + networkAgent.linkProperties, networkAgent.networkCapabilities); scheduleUnvalidatedPrompt(networkAgent); // Whether a particular NetworkRequest listen should cause signal strength thresholds to diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 34772d062f..864a793b8f 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -25,12 +25,12 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkMisc; +import android.net.NetworkMonitorManager; import android.net.NetworkRequest; import android.net.NetworkState; import android.os.Handler; import android.os.INetworkManagementService; import android.os.Messenger; -import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; @@ -247,7 +247,7 @@ public class NetworkAgentInfo implements Comparable { public final Nat464Xlat clatd; // Set after asynchronous creation of the NetworkMonitor. - private volatile INetworkMonitor mNetworkMonitor; + private volatile NetworkMonitorManager mNetworkMonitor; private static final String TAG = ConnectivityService.class.getSimpleName(); private static final boolean VDBG = false; @@ -278,7 +278,7 @@ public class NetworkAgentInfo implements Comparable { * Inform NetworkAgentInfo that a new NetworkMonitor was created. */ public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) { - mNetworkMonitor = networkMonitor; + mNetworkMonitor = new NetworkMonitorManager(networkMonitor); } /** @@ -290,13 +290,9 @@ public class NetworkAgentInfo implements Comparable { */ public void setNetworkCapabilities(NetworkCapabilities nc) { networkCapabilities = nc; - final INetworkMonitor nm = mNetworkMonitor; + final NetworkMonitorManager nm = mNetworkMonitor; if (nm != null) { - try { - nm.notifyNetworkCapabilitiesChanged(nc); - } catch (RemoteException e) { - Log.e(TAG, "Error notifying NetworkMonitor of updated NetworkCapabilities", e); - } + nm.notifyNetworkCapabilitiesChanged(nc); } } @@ -317,11 +313,11 @@ public class NetworkAgentInfo implements Comparable { } /** - * Get the INetworkMonitor in this NetworkAgentInfo. + * Get the NetworkMonitorManager in this NetworkAgentInfo. * *

This will be null before {@link #onNetworkMonitorCreated(INetworkMonitor)} is called. */ - public INetworkMonitor networkMonitor() { + public NetworkMonitorManager networkMonitor() { return mNetworkMonitor; } From 28325f27222cae3f8ac4adeac20ace31200592e8 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 3 Jun 2019 06:04:00 -0700 Subject: [PATCH 111/130] Re-notify if the network goes to PARTIAL. If NetworkMonitor detects partial connectivity before EVENT_PROMPT_UNVALIDATED arrives, show the partial connectivity notification immediately. Re-notify partial connectivity silently if no internet notification already there. Bug: 130683832 Bug: 130766237 Test: atest com.android.server.ConnectivityServiceTest Change-Id: I7d4eddc643ec795c3961097dc1bdd314d168f6c7 Merged-In: I1b79d3faf96ffe792738935088e4ebbdfcc0d878 (cherry picked from commit 58d4e7304cfce68e338ab34022a0b29d45f42c38) --- .../java/com/android/server/ConnectivityService.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d6b4043af4..5da1a19def 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2663,6 +2663,17 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkAgent.CMD_REPORT_NETWORK_STATUS, (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), 0, redirectUrlBundle); + + // If NetworkMonitor detects partial connectivity before + // EVENT_PROMPT_UNVALIDATED arrives, show the partial connectivity notification + // immediately. Re-notify partial connectivity silently if no internet + // notification already there. + if (!wasPartial && nai.partialConnectivity) { + // Remove delayed message if there is a pending message. + mHandler.removeMessages(EVENT_PROMPT_UNVALIDATED, nai.network); + handlePromptUnvalidated(nai.network); + } + if (wasValidated && !nai.lastValidated) { handleNetworkUnvalidated(nai); } From 97e3775df4b453680a729d10d0e82f4ab4977444 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 4 Jun 2019 05:26:38 -0700 Subject: [PATCH 112/130] Fix cannot create Nat-T keepalive on mobile data Currently phone process fail to unparcel NattKeepalivePacketData since it is not in framework. Moves NattKeepalivePacketData to framework to make it can be utilized by telephony. This change also removes the error feedback triggered by calling add keepalive packet filter to an unsupported network agent. This is misinterpreted by KeepaliveTracker that start keepalive is failing. Bug: 134048171 Test: 1. atest android.net.cts.ConnectivityManagerTest#testSocketKeepaliveLimitTelephony 2. atest android.net.cts.ConnectivityManagerTest 3. atest FrameworksNetTests 4. atest FrameworksTelephonyTests Merged-In: If630d5b339aa722717258c721daa8ead8c431e2d Change-Id: Ic0f168be6f5a6263a5e0565b6381dcb5c645660f (cherry picked from commit 9ede677bb2c081ccdc41c8c3c19c949114bcc138) --- .../android/net/NattKeepalivePacketData.java | 51 ++++++++++++++----- core/java/android/net/NetworkAgent.java | 2 - .../server/connectivity/KeepaliveTracker.java | 1 + 3 files changed, 38 insertions(+), 16 deletions(-) rename {services/net => core}/java/android/net/NattKeepalivePacketData.java (66%) diff --git a/services/net/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java similarity index 66% rename from services/net/java/android/net/NattKeepalivePacketData.java rename to core/java/android/net/NattKeepalivePacketData.java index 06838fe655..a77c244d6b 100644 --- a/services/net/java/android/net/NattKeepalivePacketData.java +++ b/core/java/android/net/NattKeepalivePacketData.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 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. @@ -19,9 +19,9 @@ package android.net; import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; import static android.net.SocketKeepalive.ERROR_INVALID_PORT; -import android.annotation.NonNull; import android.net.SocketKeepalive.InvalidPacketException; import android.net.util.IpUtils; +import android.os.Parcel; import android.os.Parcelable; import android.system.OsConstants; @@ -79,17 +79,40 @@ public final class NattKeepalivePacketData extends KeepalivePacketData implement return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array()); } - /** - * Convert this NattKeepalivePacketData to a NattKeepalivePacketDataParcelable. - */ - @NonNull - public NattKeepalivePacketDataParcelable toStableParcelable() { - final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable(); - - parcel.srcAddress = srcAddress.getAddress(); - parcel.srcPort = srcPort; - parcel.dstAddress = dstAddress.getAddress(); - parcel.dstPort = dstPort; - return parcel; + /** Parcelable Implementation */ + public int describeContents() { + return 0; } + + /** Write to parcel */ + public void writeToParcel(Parcel out, int flags) { + out.writeString(srcAddress.getHostAddress()); + out.writeString(dstAddress.getHostAddress()); + out.writeInt(srcPort); + out.writeInt(dstPort); + } + + /** Parcelable Creator */ + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public NattKeepalivePacketData createFromParcel(Parcel in) { + final InetAddress srcAddress = + InetAddresses.parseNumericAddress(in.readString()); + final InetAddress dstAddress = + InetAddresses.parseNumericAddress(in.readString()); + final int srcPort = in.readInt(); + final int dstPort = in.readInt(); + try { + return NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort, + dstAddress, dstPort); + } catch (InvalidPacketException e) { + throw new IllegalArgumentException( + "Invalid NAT-T keepalive data: " + e.error); + } + } + + public NattKeepalivePacketData[] newArray(int size) { + return new NattKeepalivePacketData[size]; + } + }; } diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 419fa7a61d..f416fc7959 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -511,7 +511,6 @@ public abstract class NetworkAgent extends Handler { * override this method. */ protected void addKeepalivePacketFilter(Message msg) { - onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED); } /** @@ -520,7 +519,6 @@ public abstract class NetworkAgent extends Handler { * must override this method. */ protected void removeKeepalivePacketFilter(Message msg) { - onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED); } /** diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 3de2537cff..4b2e21d943 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -216,6 +216,7 @@ public class KeepaliveTracker { public String toString() { return "KeepaliveInfo [" + + " type=" + mType + " network=" + mNai.network + " startedState=" + startedStateString(mStartedState) + " " From e01696a4c499a9fa7087f20947fdb1581b9c0213 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 4 Jun 2019 14:37:26 +0900 Subject: [PATCH 113/130] Allow passing in acceptUnvalidated without explicitlySelected This will allow wifi to tell ConnectivityService that partial connectivity is acceptable even if the network is not explicitly selected. This is needed when the user selects a partial connectivity network and tells the system to connect to the network, and never to ask again. In such cases, the system must switch to the network even if it is not explicitly selected. Bug: 130766237 Test: atest FrameworksNetTests Test: unit tests in an upcoming CL Change-Id: I13465090b7b1c0bf5dc83362387a5428d77b7e1d --- core/java/android/net/NetworkAgent.java | 19 ++++++++++++++++++- .../android/server/ConnectivityService.java | 10 +++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 419fa7a61d..c70b911803 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -434,7 +434,24 @@ public abstract class NetworkAgent extends Handler { * {@link #saveAcceptUnvalidated} to respect the user's choice. */ public void explicitlySelected(boolean acceptUnvalidated) { - queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, acceptUnvalidated ? 1 : 0, 0); + explicitlySelected(true /* explicitlySelected */, acceptUnvalidated); + } + + /** + * Called by the bearer to indicate this network was manually selected by the user. + * This should be called before the NetworkInfo is marked CONNECTED so that this + * Network can be given special treatment at that time. If {@code acceptUnvalidated} is + * {@code true}, then the system will switch to this network. If it is {@code false} and the + * network cannot be validated, the system will ask the user whether to switch to this network. + * If the user confirms and selects "don't ask again", then the system will call + * {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever + * calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement + * {@link #saveAcceptUnvalidated} to respect the user's choice. + */ + public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) { + queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED, + explicitlySelected ? 1 : 0, + acceptUnvalidated ? 1 : 0); } /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 39ce4a0066..7a2aa7ede4 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2577,11 +2577,11 @@ public class ConnectivityService extends IConnectivityManager.Stub break; } case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: { - if (nai.everConnected && !nai.networkMisc.explicitlySelected) { - loge("ERROR: already-connected network explicitly selected."); + if (nai.everConnected) { + loge("ERROR: cannot call explicitlySelected on already-connected network"); } - nai.networkMisc.explicitlySelected = true; - nai.networkMisc.acceptUnvalidated = msg.arg1 == 1; + nai.networkMisc.explicitlySelected = (msg.arg1 == 1); + nai.networkMisc.acceptUnvalidated = (msg.arg1 == 1) && (msg.arg2 == 1); // Mark the network as temporarily accepting partial connectivity so that it // will be validated (and possibly become default) even if it only provides // partial internet access. Note that if user connects to partial connectivity @@ -2589,7 +2589,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // out of wifi coverage) and if the same wifi is available again, the device // will auto connect to this wifi even though the wifi has "no internet". // TODO: Evaluate using a separate setting in IpMemoryStore. - nai.networkMisc.acceptPartialConnectivity = msg.arg1 == 1; + nai.networkMisc.acceptPartialConnectivity = (msg.arg2 == 1); break; } case NetworkAgent.EVENT_SOCKET_KEEPALIVE: { From a870366aa282748cafd1f53bd8015c2ee08d258b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 4 Jun 2019 19:29:50 +0900 Subject: [PATCH 114/130] Always prompt for limited connectivity. Bug: 130766237 Test: See subsequent CL in same patch series. Change-Id: I45b4a7ba2e21c0be868939d8c7bb78891d69c48b --- .../android/server/ConnectivityService.java | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 7a2aa7ede4..a6ff37ebf7 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3633,20 +3633,37 @@ public class ConnectivityService extends IConnectivityManager.Stub mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, true); } + private boolean shouldPromptUnvalidated(NetworkAgentInfo nai) { + // Don't prompt if the network is validated, and don't prompt on captive portals + // because we're already prompting the user to sign in. + if (nai.everValidated || nai.everCaptivePortalDetected) { + return false; + } + + // If a network has partial connectivity, always prompt unless the user has already accepted + // partial connectivity and selected don't ask again. This ensures that if the device + // automatically connects to a network that has partial Internet access, the user will + // always be able to use it, either because they've already chosen "don't ask again" or + // because we have prompt them. + if (nai.partialConnectivity && !nai.networkMisc.acceptPartialConnectivity) { + return true; + } + + // If a network has no Internet access, only prompt if the network was explicitly selected + // and if the user has not already told us to use the network regardless of whether it + // validated or not. + if (nai.networkMisc.explicitlySelected && !nai.networkMisc.acceptUnvalidated) { + return true; + } + + return false; + } + private void handlePromptUnvalidated(Network network) { if (VDBG || DDBG) log("handlePromptUnvalidated " + network); NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); - // Only prompt if the network is unvalidated or network has partial internet connectivity - // and was explicitly selected by the user, and if we haven't already been told to switch - // to it regardless of whether it validated or not. Also don't prompt on captive portals - // because we're already prompting the user to sign in. - if (nai == null || nai.everValidated || nai.everCaptivePortalDetected - || !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated - // TODO: Once the value of acceptPartialConnectivity is moved to IpMemoryStore, - // we should reevaluate how to handle acceptPartialConnectivity when network just - // connected. - || nai.networkMisc.acceptPartialConnectivity) { + if (nai == null || !shouldPromptUnvalidated(nai)) { return; } From 2cce2e74d736d0f12d39c016216a43e2824aece7 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 5 Jun 2019 16:08:37 +0900 Subject: [PATCH 115/130] Don't use a high-priority notification on auto-join. If the device connects to a network automatically and not through user action, a high-priority notification is intrusive and is inconsistent with other networking notifications, which are usually only high priority if the network is manually selected. Bug: 130766237 Test: see next CL in patch series Change-Id: I8824f2d1a0efeb6cb75e430ef5159ebce0018779 --- .../com/android/server/ConnectivityService.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index a6ff37ebf7..a2abf26891 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3599,21 +3599,31 @@ public class ConnectivityService extends IConnectivityManager.Stub private void showNetworkNotification(NetworkAgentInfo nai, NotificationType type) { final String action; + final boolean highPriority; switch (type) { case LOGGED_IN: action = Settings.ACTION_WIFI_SETTINGS; mHandler.removeMessages(EVENT_TIMEOUT_NOTIFICATION); mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NOTIFICATION, nai.network.netId, 0), TIMEOUT_NOTIFICATION_DELAY_MS); + // High priority because it is a direct result of the user logging in to a portal. + highPriority = true; break; case NO_INTERNET: action = ConnectivityManager.ACTION_PROMPT_UNVALIDATED; + // High priority because it is only displayed for explicitly selected networks. + highPriority = true; break; case LOST_INTERNET: action = ConnectivityManager.ACTION_PROMPT_LOST_VALIDATION; + // High priority because it could help the user avoid unexpected data usage. + highPriority = true; break; case PARTIAL_CONNECTIVITY: action = ConnectivityManager.ACTION_PROMPT_PARTIAL_CONNECTIVITY; + // Don't bother the user with a high-priority notification if the network was not + // explicitly selected by the user. + highPriority = nai.networkMisc.explicitlySelected; break; default: Slog.wtf(TAG, "Unknown notification type " + type); @@ -3630,7 +3640,8 @@ public class ConnectivityService extends IConnectivityManager.Stub PendingIntent pendingIntent = PendingIntent.getActivityAsUser( mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); - mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, true); + + mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, highPriority); } private boolean shouldPromptUnvalidated(NetworkAgentInfo nai) { From f97132185a7624c0d648d7994b487bdd6c1866b1 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 6 Jun 2019 23:59:01 +0000 Subject: [PATCH 116/130] Revert "Add one more test for VPN usage stats." This reverts commit 20204cdf6a2a41408e036d87993241f66362a2d0. Reason for revert: This change has been implicated in 4-way deadlocks as seen in b/134244752. Bug: 134244752 Change-Id: I64b48d575f2e6ec4cb7d2d100a859a30af0501dc --- .../server/net/NetworkStatsServiceTest.java | 46 +------------------ 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index d9f2c201fe..66a267665e 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -62,6 +62,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -1029,51 +1030,6 @@ public class NetworkStatsServiceTest { assertUidTotal(sTemplateWifi, UID_VPN, 300L, 0L, 150L, 0L, 2); } - @Test - public void vpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception { - // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). - expectDefaultSettings(); - NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()}; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; - expectNetworkStatsUidDetail(buildEmptyStats()); - expectBandwidthControlCheck(); - - mService.forceUpdateIfaces( - new Network[] {WIFI_NETWORK, VPN_NETWORK}, - vpnInfos, - networkStates, - getActiveIface(networkStates)); - // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption - // overhead per packet): - // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED - // over VPN. - // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE - // over VPN. - // Additionally, the VPN sends 6000 bytes (600 packets) of its own traffic into the tun - // interface (passing that traffic to the VPN endpoint), and receives 5000 bytes (500 - // packets) from it. Including overhead that is 6600/5500 bytes. - // VPN sent 8250 bytes (750 packets), and received 8800 (800 packets) over WiFi. - // Of 8250 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes - // attributed to UID_BLUE, and 6750 bytes attributed to UID_VPN. - // Of 8800 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes - // attributed to UID_BLUE, and 5800 bytes attributed to UID_VPN. - incrementCurrentTime(HOUR_IN_MILLIS); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 1000L, 100L, 1L) - .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 500L, 50L, 1L) - .addValues(TUN_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 5000L, 500L, 6000L, 600L, 1L) - // VPN received 8800 bytes over WiFi in background (SET_DEFAULT). - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 8800L, 800L, 0L, 0L, 1L) - // VPN sent 8250 bytes over WiFi in foreground (SET_FOREGROUND). - .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 8250L, 750L, 1L)); - - forcePollAndWaitForIdle(); - - assertUidTotal(sTemplateWifi, UID_RED, 2000L, 200L, 1000L, 100L, 1); - assertUidTotal(sTemplateWifi, UID_BLUE, 1000L, 100L, 500L, 50L, 1); - assertUidTotal(sTemplateWifi, UID_VPN, 5800L, 500L, 6750L, 600L, 2); - } - @Test public void vpnWithOneUnderlyingIface_withCompression() throws Exception { // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). From a293c0644b3d4693ebfe10f9c016e5cdf8d198cf Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 6 Jun 2019 17:06:39 -0700 Subject: [PATCH 117/130] Revert "Addressing comments for http://ag/7700679." This reverts commit 78d5ac4f8f5dfbd0b771f1ade8b28914074d5a2a. Reason for revert: This change has been implicated in 4-way deadlocks as seen in b/134244752. Bug: 134244752 Change-Id: I5fbb3443a39a21fc9d96442726cd10d20e8d61cd --- .../android/server/ConnectivityService.java | 4 +- .../server/net/NetworkStatsServiceTest.java | 115 ++++-------------- 2 files changed, 26 insertions(+), 93 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index a2abf26891..7e7fa1f483 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4396,7 +4396,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // the underlyingNetworks list. if (underlyingNetworks == null) { NetworkAgentInfo defaultNai = getDefaultNetwork(); - if (defaultNai != null) { + if (defaultNai != null && defaultNai.linkProperties != null) { underlyingNetworks = new Network[] { defaultNai.network }; } } @@ -4404,7 +4404,7 @@ public class ConnectivityService extends IConnectivityManager.Stub List interfaces = new ArrayList<>(); for (Network network : underlyingNetworks) { LinkProperties lp = getLinkProperties(network); - if (lp != null && !TextUtils.isEmpty(lp.getInterfaceName())) { + if (lp != null) { interfaces.add(lp.getInterfaceName()); } } diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 66a267665e..e35c34affd 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -930,65 +930,6 @@ public class NetworkStatsServiceTest { assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0); } - @Test - public void vpnRewriteTrafficThroughItself() throws Exception { - // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). - expectDefaultSettings(); - NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()}; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; - expectNetworkStatsUidDetail(buildEmptyStats()); - expectBandwidthControlCheck(); - - mService.forceUpdateIfaces( - new Network[] {WIFI_NETWORK, VPN_NETWORK}, - vpnInfos, - networkStates, - getActiveIface(networkStates)); - // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption - // overhead per packet): - // - // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED - // over VPN. - // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE - // over VPN. - // - // VPN UID rewrites packets read from TUN back to TUN, plus some of its own traffic - // (100 bytes). - incrementCurrentTime(HOUR_IN_MILLIS); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 5) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 1000L, 100L, 1L) - .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 500L, 50L, 1L) - // VPN rewrites all the packets read from TUN + 100 additional bytes of VPN's - // own traffic. - .addValues(TUN_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 0L, 0L, 1600L, 160L, 2L) - // VPN sent 1760 bytes over WiFi in foreground (SET_FOREGROUND) i.e. 1600 - // bytes (160 packets) + 1 byte/packet overhead (=160 bytes). - .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 1760L, 176L, 1L) - // VPN received 3300 bytes over WiFi in background (SET_DEFAULT) i.e. 3000 bytes - // (300 packets) + 1 byte/packet encryption overhead (=300 bytes). - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 3300L, 300L, 0L, 0L, 1L)); - - forcePollAndWaitForIdle(); - - // Verify increased TUN usage by UID_VPN does not get attributed to other apps. - NetworkStats tunStats = - mService.getDetailedUidStats(new String[] {TUN_IFACE}); - assertValues( - tunStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 2000L, 200L, 1000L, 100L, 1); - assertValues( - tunStats, TUN_IFACE, UID_BLUE, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 1000L, 100L, 500L, 50L, 1); - assertValues( - tunStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 0L, 0L, 1600L, 160L, 2); - - // Verify correct attribution over WiFi. - assertUidTotal(sTemplateWifi, UID_RED, 2000L, 200L, 1000L, 100L, 1); - assertUidTotal(sTemplateWifi, UID_BLUE, 1000L, 100L, 500L, 50L, 1); - assertUidTotal(sTemplateWifi, UID_VPN, 300L, 0L, 260L, 26L, 2); - } - @Test public void vpnWithOneUnderlyingIface() throws Exception { // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). @@ -1005,29 +946,25 @@ public class NetworkStatsServiceTest { getActiveIface(networkStates)); // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption // overhead per packet): - // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED - // over VPN. - // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE - // over VPN. - // VPN sent 1650 bytes (150 packets), and received 3300 (300 packets) over WiFi. - // Of 1650 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes - // attributed to UID_BLUE, and 150 bytes attributed to UID_VPN. - // Of 3300 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes - // attributed to UID_BLUE, and 300 bytes attributed to UID_VPN. + // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. + // 500 bytes (50 packets) were sent/received by UID_BLUE over VPN. + // VPN sent/received 1650 bytes (150 packets) over WiFi. + // Of 1650 bytes over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes attributed to + // UID_BLUE, and 150 bytes attributed to UID_VPN for both rx/tx traffic. incrementCurrentTime(HOUR_IN_MILLIS); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 1000L, 100L, 1L) - .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 500L, 50L, 1L) - // VPN received 3300 bytes over WiFi in background (SET_DEFAULT). - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 3300L, 300L, 0L, 0L, 1L) + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L) + .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L) + // VPN received 1650 bytes over WiFi in background (SET_DEFAULT). + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 0L, 0L, 1L) // VPN sent 1650 bytes over WiFi in foreground (SET_FOREGROUND). .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 1650L, 150L, 1L)); forcePollAndWaitForIdle(); - assertUidTotal(sTemplateWifi, UID_RED, 2000L, 200L, 1000L, 100L, 1); - assertUidTotal(sTemplateWifi, UID_BLUE, 1000L, 100L, 500L, 50L, 1); - assertUidTotal(sTemplateWifi, UID_VPN, 300L, 0L, 150L, 0L, 2); + assertUidTotal(sTemplateWifi, UID_RED, 1000L, 100L, 1000L, 100L, 1); + assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1); + assertUidTotal(sTemplateWifi, UID_VPN, 150L, 0L, 150L, 0L, 2); } @Test @@ -1131,28 +1068,24 @@ public class NetworkStatsServiceTest { getActiveIface(networkStates)); // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption // overhead per packet): - // 1000 bytes (100 packets) were sent, and 500 bytes (50 packets) received by UID_RED over - // VPN. - // VPN sent 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell. - // And, it received 330 bytes (30 packets) over WiFi and 220 bytes (20 packets) over Cell. - // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for sent (tx) - // traffic. For received (rx) traffic, expect 300 bytes over WiFi and 200 bytes over Cell. - // - // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for tx traffic. - // And, 30 bytes over WiFi and 20 bytes over Cell for rx traffic. + // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. + // VPN sent/received 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell. + // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for both + // rx/tx. + // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for both rx/tx. incrementCurrentTime(HOUR_IN_MILLIS); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 500L, 50L, 1000L, 100L, 2L) - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 330L, 30L, 660L, 60L, 1L) - .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 220L, 20L, 440L, 40L, 1L)); + .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L) + .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 660L, 60L, 660L, 60L, 1L) + .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 440L, 40L, 440L, 40L, 1L)); forcePollAndWaitForIdle(); - assertUidTotal(sTemplateWifi, UID_RED, 300L, 30L, 600L, 60L, 1); - assertUidTotal(sTemplateWifi, UID_VPN, 30L, 0L, 60L, 0L, 1); + assertUidTotal(sTemplateWifi, UID_RED, 600L, 60L, 600L, 60L, 1); + assertUidTotal(sTemplateWifi, UID_VPN, 60L, 0L, 60L, 0L, 1); - assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 200L, 20L, 400L, 40L, 1); - assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 20L, 0L, 40L, 0L, 1); + assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 400L, 40L, 400L, 40L, 1); + assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 40L, 0L, 40L, 0L, 1); } @Test From ebf6303f1dbb193ee3308c461cf7018c59179458 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 6 Jun 2019 17:06:48 -0700 Subject: [PATCH 118/130] Revert "NetworkStatsService: Fix getDetailedUidStats to take VPNs into account." This reverts commit e7094673d53330ce501d3ccb946a91ded1ba7ccb. Reason for revert: This change has been implicated in 4-way deadlocks as seen in b/134244752. Bug: 134244752 Change-Id: I0c00e8f0e30cee987b71b561079a97bf09d4dae4 --- .../java/android/net/NetworkStatsTest.java | 31 ---- .../server/net/NetworkStatsServiceTest.java | 148 +----------------- 2 files changed, 6 insertions(+), 173 deletions(-) diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index c16a0f4466..9ed6cb9b45 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -812,37 +812,6 @@ public class NetworkStatsTest { assertEquals(entry2, stats.getValues(1, null)); } - @Test - public void testFilterDebugEntries() { - NetworkStats.Entry entry1 = new NetworkStats.Entry( - "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); - - NetworkStats.Entry entry2 = new NetworkStats.Entry( - "test2", 10101, SET_DBG_VPN_IN, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); - - NetworkStats.Entry entry3 = new NetworkStats.Entry( - "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); - - NetworkStats.Entry entry4 = new NetworkStats.Entry( - "test2", 10101, SET_DBG_VPN_OUT, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); - - NetworkStats stats = new NetworkStats(TEST_START, 4) - .addValues(entry1) - .addValues(entry2) - .addValues(entry3) - .addValues(entry4); - - stats.filterDebugEntries(); - - assertEquals(2, stats.size()); - assertEquals(entry1, stats.getValues(0, null)); - assertEquals(entry3, stats.getValues(1, null)); - } - @Test public void testApply464xlatAdjustments() { final String v4Iface = "v4-wlan0"; diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index e35c34affd..c46534c8d0 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -57,7 +57,6 @@ import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_PO import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -217,16 +216,11 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(buildEmptyStats()); expectSystemReady(); - assertNull(mService.getTunAdjustedStats()); mService.systemReady(); - // Verify that system ready fetches realtime stats and initializes tun adjusted stats. - verify(mNetManager).getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL); - assertNotNull("failed to initialize TUN adjusted stats", mService.getTunAdjustedStats()); - assertEquals(0, mService.getTunAdjustedStats().size()); - mSession = mService.openSession(); assertNotNull("openSession() failed", mSession); + // catch INetworkManagementEventObserver during systemReady() ArgumentCaptor networkObserver = ArgumentCaptor.forClass(INetworkManagementEventObserver.class); @@ -739,13 +733,11 @@ public class NetworkStatsServiceTest { NetworkStats stats = mService.getDetailedUidStats(ifaceFilter); - // mNetManager#getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL) has following invocations: - // 1) NetworkStatsService#systemReady from #setUp. - // 2) mService#forceUpdateIfaces in the test above. - // 3) Finally, mService#getDetailedUidStats. - verify(mNetManager, times(3)).getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL); - assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), TEST_IFACE)); - assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), stackedIface)); + verify(mNetManager, times(1)).getNetworkStatsUidDetail(eq(UID_ALL), argThat(ifaces -> + ifaces != null && ifaces.length == 2 + && ArrayUtils.contains(ifaces, TEST_IFACE) + && ArrayUtils.contains(ifaces, stackedIface))); + assertEquals(2, stats.size()); assertEquals(uidStats, stats.getValues(0, null)); assertEquals(tetheredStats1, stats.getValues(1, null)); @@ -1165,134 +1157,6 @@ public class NetworkStatsServiceTest { assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1100L, 100L, 1100L, 100L, 1); } - @Test - public void recordSnapshot_migratesTunTrafficAndUpdatesTunAdjustedStats() throws Exception { - assertEquals(0, mService.getTunAdjustedStats().size()); - // VPN using WiFi (TEST_IFACE). - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; - expectBandwidthControlCheck(); - // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption - // overhead per packet): - // 1000 bytes (100 packets) were downloaded by UID_RED over VPN. - // VPN received 1100 bytes (100 packets) over WiFi. - incrementCurrentTime(HOUR_IN_MILLIS); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L) - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L)); - - // this should lead to NSS#recordSnapshotLocked - mService.forceUpdateIfaces( - new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */); - - // Verify TUN adjusted stats have traffic migrated correctly. - // Of 1100 bytes VPN received over WiFi, expect 1000 bytes attributed to UID_RED and 100 - // bytes attributed to UID_VPN. - NetworkStats tunAdjStats = mService.getTunAdjustedStats(); - assertValues( - tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0); - assertValues( - tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0); - } - - @Test - public void getDetailedUidStats_migratesTunTrafficAndUpdatesTunAdjustedStats() - throws Exception { - assertEquals(0, mService.getTunAdjustedStats().size()); - // VPN using WiFi (TEST_IFACE). - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; - expectBandwidthControlCheck(); - mService.forceUpdateIfaces( - new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */); - // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption - // overhead per packet): - // 1000 bytes (100 packets) were downloaded by UID_RED over VPN. - // VPN received 1100 bytes (100 packets) over WiFi. - incrementCurrentTime(HOUR_IN_MILLIS); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L) - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L)); - - mService.getDetailedUidStats(INTERFACES_ALL); - - // Verify internally maintained TUN adjusted stats - NetworkStats tunAdjStats = mService.getTunAdjustedStats(); - // Verify stats for TEST_IFACE (WiFi): - // Of 1100 bytes VPN received over WiFi, expect 1000 bytes attributed to UID_RED and 100 - // bytes attributed to UID_VPN. - assertValues( - tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0); - assertValues( - tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0); - // Verify stats for TUN_IFACE; only UID_RED should have usage on it. - assertValues( - tunAdjStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0); - assertValues( - tunAdjStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 0L, 0L, 0L, 0L, 0); - - // lets assume that since last time, VPN received another 1100 bytes (same assumptions as - // before i.e. UID_RED downloaded another 1000 bytes). - incrementCurrentTime(HOUR_IN_MILLIS); - // Note - NetworkStatsFactory returns counters that are monotonically increasing. - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 2000L, 200L, 0L, 0L, 0L) - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 2200L, 200L, 0L, 0L, 0L)); - - mService.getDetailedUidStats(INTERFACES_ALL); - - tunAdjStats = mService.getTunAdjustedStats(); - // verify TEST_IFACE stats: - assertValues( - tunAdjStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 2000L, 200L, 0L, 0L, 0); - assertValues( - tunAdjStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 200L, 0L, 0L, 0L, 0); - // verify TUN_IFACE stats: - assertValues( - tunAdjStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 2000L, 200L, 0L, 0L, 0); - assertValues( - tunAdjStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 0L, 0L, 0L, 0L, 0); - } - - @Test - public void getDetailedUidStats_returnsCorrectStatsWithVpnRunning() throws Exception { - // VPN using WiFi (TEST_IFACE). - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; - expectBandwidthControlCheck(); - mService.forceUpdateIfaces( - new Network[0], vpnInfos, new NetworkState[0], null /* activeIface */); - // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption - // overhead per packet): - // 1000 bytes (100 packets) were downloaded by UID_RED over VPN. - // VPN received 1100 bytes (100 packets) over WiFi. - incrementCurrentTime(HOUR_IN_MILLIS); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 0L, 0L, 0L) - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 0L, 0L, 0L)); - - // Query realtime stats for TEST_IFACE. - NetworkStats queriedStats = - mService.getDetailedUidStats(new String[] {TEST_IFACE}); - - assertEquals(HOUR_IN_MILLIS, queriedStats.getElapsedRealtime()); - // verify that returned stats are only for TEST_IFACE and VPN traffic is migrated correctly. - assertEquals(new String[] {TEST_IFACE}, queriedStats.getUniqueIfaces()); - assertValues( - queriedStats, TEST_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 1000L, 100L, 0L, 0L, 0); - assertValues( - queriedStats, TEST_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, 100L, 0L, 0L, 0L, 0); - } - @Test public void testRegisterUsageCallback() throws Exception { // pretend that wifi network comes online; service should ask about full From 4c94d3051dc109eb2bde2c17b4b59d63f4d35132 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 6 Jun 2019 17:08:02 -0700 Subject: [PATCH 119/130] Revert "Take all VPN underlying networks into account when migrating traffic for" This reverts commit 97482de1fd3824be733c11a9e0a2c1ad0a2eb702. Reason for revert: This change has been implicated in 4-way deadlocks as seen in b/134244752. Bug: 134244752 Change-Id: Ibdaad3a4cbf0d8ef1ed53cfab1e454b9b878bae9 --- .../android/server/ConnectivityService.java | 27 ++-- .../java/android/net/NetworkStatsTest.java | 4 +- .../server/net/NetworkStatsServiceTest.java | 142 +----------------- 3 files changed, 19 insertions(+), 154 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 7e7fa1f483..5027a124e0 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4383,7 +4383,7 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * @return VPN information for accounting, or null if we can't retrieve all required - * information, e.g underlying ifaces. + * information, e.g primary underlying iface. */ @Nullable private VpnInfo createVpnInfo(Vpn vpn) { @@ -4395,24 +4395,17 @@ public class ConnectivityService extends IConnectivityManager.Stub // see VpnService.setUnderlyingNetworks()'s javadoc about how to interpret // the underlyingNetworks list. if (underlyingNetworks == null) { - NetworkAgentInfo defaultNai = getDefaultNetwork(); - if (defaultNai != null && defaultNai.linkProperties != null) { - underlyingNetworks = new Network[] { defaultNai.network }; + NetworkAgentInfo defaultNetwork = getDefaultNetwork(); + if (defaultNetwork != null && defaultNetwork.linkProperties != null) { + info.primaryUnderlyingIface = getDefaultNetwork().linkProperties.getInterfaceName(); + } + } else if (underlyingNetworks.length > 0) { + LinkProperties linkProperties = getLinkProperties(underlyingNetworks[0]); + if (linkProperties != null) { + info.primaryUnderlyingIface = linkProperties.getInterfaceName(); } } - if (underlyingNetworks != null && underlyingNetworks.length > 0) { - List interfaces = new ArrayList<>(); - for (Network network : underlyingNetworks) { - LinkProperties lp = getLinkProperties(network); - if (lp != null) { - interfaces.add(lp.getInterfaceName()); - } - } - if (!interfaces.isEmpty()) { - info.underlyingIfaces = interfaces.toArray(new String[interfaces.size()]); - } - } - return info.underlyingIfaces == null ? null : info; + return info.primaryUnderlyingIface == null ? null : info; } /** diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index 9ed6cb9b45..b5b0384ca5 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -569,7 +569,7 @@ public class NetworkStatsTest { .addValues(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L); - delta.migrateTun(tunUid, tunIface, new String[] {underlyingIface}); + assertTrue(delta.toString(), delta.migrateTun(tunUid, tunIface, underlyingIface)); assertEquals(20, delta.size()); // tunIface and TEST_IFACE entries are not changed. @@ -650,7 +650,7 @@ public class NetworkStatsTest { .addValues(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L); - delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface}); + assertTrue(delta.migrateTun(tunUid, tunIface, underlyingIface)); assertEquals(9, delta.size()); // tunIface entries should not be changed. diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index c46534c8d0..bce526d3ae 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -927,7 +927,7 @@ public class NetworkStatsServiceTest { // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). expectDefaultSettings(); NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()}; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)}; expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); @@ -947,10 +947,8 @@ public class NetworkStatsServiceTest { expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L) .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L) - // VPN received 1650 bytes over WiFi in background (SET_DEFAULT). - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 0L, 0L, 1L) - // VPN sent 1650 bytes over WiFi in foreground (SET_FOREGROUND). - .addValues(TEST_IFACE, UID_VPN, SET_FOREGROUND, TAG_NONE, 0L, 0L, 1650L, 150L, 1L)); + .addValues( + TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 1650L, 150L, 2L)); forcePollAndWaitForIdle(); @@ -964,7 +962,7 @@ public class NetworkStatsServiceTest { // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE). expectDefaultSettings(); NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()}; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)}; expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); @@ -994,132 +992,6 @@ public class NetworkStatsServiceTest { assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0); } - @Test - public void vpnWithTwoUnderlyingIfaces_packetDuplication() throws Exception { - // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and - // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set. - // Additionally, VPN is duplicating traffic across both WiFi and Cell. - expectDefaultSettings(); - NetworkState[] networkStates = - new NetworkState[] { - buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState() - }; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})}; - expectNetworkStatsUidDetail(buildEmptyStats()); - expectBandwidthControlCheck(); - - mService.forceUpdateIfaces( - new Network[] {WIFI_NETWORK, VPN_NETWORK}, - vpnInfos, - networkStates, - getActiveIface(networkStates)); - // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption - // overhead per packet): - // 1000 bytes (100 packets) were sent/received by UID_RED and UID_BLUE over VPN. - // VPN sent/received 4400 bytes (400 packets) over both WiFi and Cell (8800 bytes in total). - // Of 8800 bytes over WiFi/Cell, expect: - // - 500 bytes rx/tx each over WiFi/Cell attributed to both UID_RED and UID_BLUE. - // - 1200 bytes rx/tx each over WiFi/Cell for VPN_UID. - incrementCurrentTime(HOUR_IN_MILLIS); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 4) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L) - .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L) - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 2200L, 200L, 2200L, 200L, 2L) - .addValues( - TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 2200L, 200L, 2200L, 200L, 2L)); - - forcePollAndWaitForIdle(); - - assertUidTotal(sTemplateWifi, UID_RED, 500L, 50L, 500L, 50L, 1); - assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1); - assertUidTotal(sTemplateWifi, UID_VPN, 1200L, 100L, 1200L, 100L, 2); - - assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 500L, 50L, 500L, 50L, 1); - assertUidTotal(buildTemplateMobileWildcard(), UID_BLUE, 500L, 50L, 500L, 50L, 1); - assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1200L, 100L, 1200L, 100L, 2); - } - - @Test - public void vpnWithTwoUnderlyingIfaces_splitTraffic() throws Exception { - // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and - // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set. - // Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell. - expectDefaultSettings(); - NetworkState[] networkStates = - new NetworkState[] { - buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState() - }; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})}; - expectNetworkStatsUidDetail(buildEmptyStats()); - expectBandwidthControlCheck(); - - mService.forceUpdateIfaces( - new Network[] {WIFI_NETWORK, VPN_NETWORK}, - vpnInfos, - networkStates, - getActiveIface(networkStates)); - // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption - // overhead per packet): - // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. - // VPN sent/received 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell. - // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for both - // rx/tx. - // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for both rx/tx. - incrementCurrentTime(HOUR_IN_MILLIS); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 2L) - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 660L, 60L, 660L, 60L, 1L) - .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 440L, 40L, 440L, 40L, 1L)); - - forcePollAndWaitForIdle(); - - assertUidTotal(sTemplateWifi, UID_RED, 600L, 60L, 600L, 60L, 1); - assertUidTotal(sTemplateWifi, UID_VPN, 60L, 0L, 60L, 0L, 1); - - assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 400L, 40L, 400L, 40L, 1); - assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 40L, 0L, 40L, 0L, 1); - } - - @Test - public void vpnWithTwoUnderlyingIfaces_splitTrafficWithCompression() throws Exception { - // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and - // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set. - // Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell. - expectDefaultSettings(); - NetworkState[] networkStates = - new NetworkState[] { - buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState() - }; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})}; - expectNetworkStatsUidDetail(buildEmptyStats()); - expectBandwidthControlCheck(); - - mService.forceUpdateIfaces( - new Network[] {WIFI_NETWORK, VPN_NETWORK}, - vpnInfos, - networkStates, - getActiveIface(networkStates)); - // create some traffic (assume 10 bytes of MTU for VPN interface: - // 1000 bytes (100 packets) were sent/received by UID_RED over VPN. - // VPN sent/received 600 bytes (60 packets) over WiFi and 200 bytes (20 packets) over Cell. - // For UID_RED, expect 600 bytes attributed over WiFi and 200 bytes over Cell for both - // rx/tx. - // UID_VPN gets nothing attributed to it (avoiding negative stats). - incrementCurrentTime(HOUR_IN_MILLIS); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 4) - .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L) - .addValues(TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 600L, 60L, 600L, 60L, 0L) - .addValues(TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 200L, 20L, 200L, 20L, 0L)); - - forcePollAndWaitForIdle(); - - assertUidTotal(sTemplateWifi, UID_RED, 600L, 60L, 600L, 60L, 0); - assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0); - - assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 200L, 20L, 200L, 20L, 0); - assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 0L, 0L, 0L, 0L, 0); - } - @Test public void vpnWithIncorrectUnderlyingIface() throws Exception { // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2), @@ -1129,7 +1001,7 @@ public class NetworkStatsServiceTest { new NetworkState[] { buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState() }; - VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(new String[] {TEST_IFACE})}; + VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)}; expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); @@ -1510,11 +1382,11 @@ public class NetworkStatsServiceTest { return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null); } - private static VpnInfo createVpnInfo(String[] underlyingIfaces) { + private static VpnInfo createVpnInfo(String underlyingIface) { VpnInfo info = new VpnInfo(); info.ownerUid = UID_VPN; info.vpnIface = TUN_IFACE; - info.underlyingIfaces = underlyingIfaces; + info.primaryUnderlyingIface = underlyingIface; return info; } From c23ae79df596fc1a0a9bc1b9622ddc1a16638825 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 11 Jun 2019 09:08:00 -0700 Subject: [PATCH 120/130] Fix race condition caused by fd reused for DnsResolver There might be a gap between fd close and fd event listener unregister. If fd is reused for another query during that gap, it might cause the query failed with no response since addOnFileDescriptorEventListener method failed. To fix this problem, we must ensure that fd event listener is unregistered before fd closing. Bug: 134310704 Test: atest DnsResolverTest Merged-In: I443bb11b15845b079ee4370a7797e692e62fa3c8 (cherry picked from commit 07de4cf82ac09f8b9f37afa9eb1b7a44b43b6fe6) Change-Id: I7041e67d8c906cbf88050e7d94245f8e15dcdbb4 --- core/java/android/net/DnsResolver.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java index 7a85dcbfc8..0b1a84534e 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -34,6 +34,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.CancellationSignal; import android.os.Looper; +import android.os.MessageQueue; import android.system.ErrnoException; import android.util.Log; @@ -466,10 +467,20 @@ public final class DnsResolver { private void registerFDListener(@NonNull Executor executor, @NonNull FileDescriptor queryfd, @NonNull Callback answerCallback, @Nullable CancellationSignal cancellationSignal, @NonNull Object lock) { - Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener( + final MessageQueue mainThreadMessageQueue = Looper.getMainLooper().getQueue(); + mainThreadMessageQueue.addOnFileDescriptorEventListener( queryfd, FD_EVENTS, (fd, events) -> { + // b/134310704 + // Unregister fd event listener before resNetworkResult is called to prevent + // race condition caused by fd reused. + // For example when querying v4 and v6, it's possible that the first query ends + // and the fd is closed before the second request starts, which might return + // the same fd for the second request. By that time, the looper must have + // unregistered the fd, otherwise another event listener can't be registered. + mainThreadMessageQueue.removeOnFileDescriptorEventListener(fd); + executor.execute(() -> { DnsResponse resp = null; ErrnoException exception = null; @@ -490,7 +501,11 @@ public final class DnsResolver { } answerCallback.onAnswer(resp.answerbuf, resp.rcode); }); - // Unregister this fd listener + + // The file descriptor has already been unregistered, so it does not really + // matter what is returned here. In spirit 0 (meaning "unregister this FD") + // is still the closest to what the looper needs to do. When returning 0, + // Looper knows to ignore the fd if it has already been unregistered. return 0; }); } From f94d57a6e5206b2dba0f8d723f9fdc9bc26719ed Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Wed, 12 Jun 2019 16:31:14 +0900 Subject: [PATCH 121/130] Restore the Private DNS settings to default mode upon network resets. Bug: 134918038 Test: atest FrameworksNetTests NetworkStackTests Test: manual test configure private dns settings (e.g. dns.google) -> connect Wi-Fi -> click "Reset Wi-Fi, mobile & Bluetooth" -> verify private dns settings is automatic -> connect Wi-Fi -> verify Internet connection. Change-Id: I13562af622d7b584d6219f74534219b7868275f9 --- .../core/java/com/android/server/ConnectivityService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5027a124e0..de9d8f5caa 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.NETID_UNSET; +import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_NONE; import static android.net.ConnectivityManager.TYPE_VPN; @@ -6952,6 +6953,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + // restore private DNS settings to default mode (opportunistic) + if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) { + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC); + } + Settings.Global.putString(mContext.getContentResolver(), Settings.Global.NETWORK_AVOID_BAD_WIFI, null); } From d9cdbc1e45d9dfdf9c4bdecd638701c5eb2291ce Mon Sep 17 00:00:00 2001 From: Heemin Seog Date: Wed, 12 Jun 2019 09:21:44 -0700 Subject: [PATCH 122/130] Change factoryReset to succeed for Settings Wrap a part of factoryReset with Binder.withCleanCallingIdentity() so that it doesn't crash thinking that a different uid connected to the network stack. Bug: 135029349 Test: build, manual Change-Id: Iea246a4c1939a4e7e35434137051835ece81d92f --- .../core/java/com/android/server/ConnectivityService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5027a124e0..1cca0b9d75 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -6901,8 +6901,10 @@ public class ConnectivityService extends IConnectivityManager.Stub final int userId = UserHandle.getCallingUserId(); - final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext); - ipMemoryStore.factoryReset(); + Binder.withCleanCallingIdentity(() -> { + final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext); + ipMemoryStore.factoryReset(); + }); // Turn airplane mode off setAirplaneMode(false); From 799bf5a8cce371e9693612b88b42263f89c2402a Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 13 Jun 2019 02:50:16 -0700 Subject: [PATCH 123/130] Suppress the wtf log for notifications that are expected PARTIAL and NO_INTERNET may happen in the real world for those transport types that provide internet. These two notification types should be reasonable notificaitons, not a terrible failure as the log. For Q, it may be too risky to display more notifications with other information instead of SSID. Thus, suppress the wtf log for these two notifications. Bug: 135043192 Test: atest FrameworksNetTests Change-Id: I35f3718fa93b403858587d918f0bc596f6c92f3e Merged-In: I91b92249dc7905aadbc59df50c3bc6da30a8590e Merged-In: Ia1c2a765b0fb0cc8d440c02533bdc15774a5a3ef (cherry picked from commit ed0a54bd07ea1c9072459bafeaf796eaa4dad4c5) --- .../NetworkNotificationManager.java | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index f6735d9834..bcf5a71344 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -178,15 +178,31 @@ public class NetworkNotificationManager { CharSequence title; CharSequence details; int icon = getIcon(transportType, notifyType); - if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) { - title = r.getString(R.string.wifi_no_internet, - WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); - details = r.getString(R.string.wifi_no_internet_detailed); - } else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY - && transportType == TRANSPORT_WIFI) { - title = r.getString(R.string.network_partial_connectivity, - WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); - details = r.getString(R.string.network_partial_connectivity_detailed); + if (notifyType == NotificationType.NO_INTERNET) { + switch (transportType) { + case TRANSPORT_WIFI: + title = r.getString(R.string.wifi_no_internet, + WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); + details = r.getString(R.string.wifi_no_internet_detailed); + break; + default: + // TODO: Display notifications for those networks that provide internet. + // except VPN. + return; + } + + } else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY) { + switch (transportType) { + case TRANSPORT_WIFI: + title = r.getString(R.string.network_partial_connectivity, + WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); + details = r.getString(R.string.network_partial_connectivity_detailed); + break; + default: + // TODO: Display notifications for those networks that provide internet. + // except VPN. + return; + } } else if (notifyType == NotificationType.LOST_INTERNET && transportType == TRANSPORT_WIFI) { title = r.getString(R.string.wifi_no_internet, From 5411bda0ca110a93f87a5b1d616e1a5f1c7c221c Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 17 Jun 2019 04:42:04 -0700 Subject: [PATCH 124/130] Simplification of code to prevent a Log.wtf in expected cases. This mostly serves to unindent code to make it locally more readable. It is a functional no-op. Bug: 135043192 Test: atest FrameworksNetTests Merged-In: Iad0e9a28670e96a3c953518a0d0ccd77e2f2fa80 Change-Id: I80bebcd04c277f6e4b0665fe1253b2309e3bc535 (cherry picked from commit e1f5759319a4559b3cf89029449878dc56f92bb7) --- .../NetworkNotificationManager.java | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index bcf5a71344..077c4057a3 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -178,31 +178,15 @@ public class NetworkNotificationManager { CharSequence title; CharSequence details; int icon = getIcon(transportType, notifyType); - if (notifyType == NotificationType.NO_INTERNET) { - switch (transportType) { - case TRANSPORT_WIFI: - title = r.getString(R.string.wifi_no_internet, - WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); - details = r.getString(R.string.wifi_no_internet_detailed); - break; - default: - // TODO: Display notifications for those networks that provide internet. - // except VPN. - return; - } - - } else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY) { - switch (transportType) { - case TRANSPORT_WIFI: - title = r.getString(R.string.network_partial_connectivity, - WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); - details = r.getString(R.string.network_partial_connectivity_detailed); - break; - default: - // TODO: Display notifications for those networks that provide internet. - // except VPN. - return; - } + if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) { + title = r.getString(R.string.wifi_no_internet, + WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); + details = r.getString(R.string.wifi_no_internet_detailed); + } else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY + && transportType == TRANSPORT_WIFI) { + title = r.getString(R.string.network_partial_connectivity, + WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); + details = r.getString(R.string.network_partial_connectivity_detailed); } else if (notifyType == NotificationType.LOST_INTERNET && transportType == TRANSPORT_WIFI) { title = r.getString(R.string.wifi_no_internet, @@ -248,6 +232,11 @@ public class NetworkNotificationManager { title = r.getString(R.string.network_switch_metered, toTransport); details = r.getString(R.string.network_switch_metered_detail, toTransport, fromTransport); + } else if (notifyType == NotificationType.NO_INTERNET + || notifyType == NotificationType.PARTIAL_CONNECTIVITY) { + // NO_INTERNET and PARTIAL_CONNECTIVITY notification for non-WiFi networks + // are sent, but they are not implemented yet. + return; } else { Slog.wtf(TAG, "Unknown notification type " + notifyType + " on network transport " + getTransportName(transportType)); From c34b699c2e4d457aa7ad1db34ba2d7277605641b Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 17 Jun 2019 08:20:11 -0700 Subject: [PATCH 125/130] Remove the <= P restriction for WIFI_P2P This is still sent in an intent. Bug: 131764329 Fixes: 131764329 Merged-In: I56c86b0c1912064d5a642991df32d2cefb6a8d5b Change-Id: I64b9d632be97dc51e6085162371bb8c19f410258 (cherry picked from commit e546cb0bd16b7359feeb3c46ba52e64cf91ae4d3) --- core/java/android/net/ConnectivityManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index fbfbfc04d8..111a8c48a4 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -655,7 +655,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) + @UnsupportedAppUsage public static final int TYPE_WIFI_P2P = 13; /** From ca8b6ed19f6baf18fd7292881e0b973b80d83d44 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 19 Jun 2019 07:29:11 -0700 Subject: [PATCH 126/130] Move the test of minimum supported keepalive slots to CTS This change also enables log when keepalive is started. Bug: 134352656 Test: 1. atest android.net.cts.ConnectivityManagerTest#testSocketKeepaliveLimitTelephony 2. atest FrameworksNetTests Merged-In: I408750fa0bceb0c1c26afb5fead4e44fb824fbc1 Change-Id: Ib9b06d3458782a648a2f5b8fd5a9ca1d34bd11f9 (cherry picked from commit aed835f086440f721c279e33d6b5d4b4bc270296) --- core/java/android/net/util/KeepaliveUtils.java | 8 +------- .../com/android/server/connectivity/KeepaliveTracker.java | 2 +- tests/net/java/android/net/util/KeepaliveUtilsTest.kt | 1 - 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/util/KeepaliveUtils.java b/core/java/android/net/util/KeepaliveUtils.java index 569fed1fc9..bfc4563fbf 100644 --- a/core/java/android/net/util/KeepaliveUtils.java +++ b/core/java/android/net/util/KeepaliveUtils.java @@ -34,9 +34,6 @@ public final class KeepaliveUtils { public static final String TAG = "KeepaliveUtils"; - // Minimum supported keepalive count per transport if the network supports keepalive. - public static final int MIN_SUPPORTED_KEEPALIVE_COUNT = 3; - public static class KeepaliveDeviceConfigurationException extends AndroidRuntimeException { public KeepaliveDeviceConfigurationException(final String msg) { super(msg); @@ -84,10 +81,7 @@ public final class KeepaliveUtils { throw new KeepaliveDeviceConfigurationException("Invalid transport " + transport); } - // Customized values should be either 0 to indicate the network doesn't support - // keepalive offload, or a positive value that is at least - // MIN_SUPPORTED_KEEPALIVE_COUNT if supported. - if (supported != 0 && supported < MIN_SUPPORTED_KEEPALIVE_COUNT) { + if (supported < 0) { throw new KeepaliveDeviceConfigurationException( "Invalid supported count " + supported + " for " + NetworkCapabilities.transportNameOf(transport)); diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 4b2e21d943..cb6424540f 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -564,7 +564,7 @@ public class KeepaliveTracker { if (KeepaliveInfo.STARTING == ki.mStartedState) { if (SUCCESS == reason) { // Keepalive successfully started. - if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name()); + Log.d(TAG, "Started keepalive " + slot + " on " + nai.name()); ki.mStartedState = KeepaliveInfo.STARTED; try { ki.mCallback.onStarted(slot); diff --git a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt index 814e06e311..8ea226db93 100644 --- a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt +++ b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt @@ -78,7 +78,6 @@ class KeepaliveUtilsTest { assertRunWithException(arrayOf("5")) // Check resource with invalid slots value. - assertRunWithException(arrayOf("2,2")) assertRunWithException(arrayOf("3,-1")) // Check resource with invalid transport type. From 03e193c8a7b93f39cfa17e6b2727d340f2ef8f8c Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 19 Jun 2019 07:28:53 -0700 Subject: [PATCH 127/130] Correct value of supported keepalive count for cellular Cellular only supports 1 keepalive connection so correct the default supported value to 1. Bug: 134037217 Bug: 134352656 Test: - atest FrameworksNetTests - atest android.net.cts.ConnectivityManagerTest \ #testSocketKeepaliveLimitTelephony Merged-In: Ia3761f2e78d54866bb2e156d58004396bbc8adc3 Change-Id: If833b813ba00eeff913160598f1ea9c74e6e35d8 (cherry picked from commit 680abbb591d9c084d1a1e3f9dea1ed8d4e3b1ae8) --- core/java/android/net/SocketKeepalive.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java index 46eddde968..ec73866a64 100644 --- a/core/java/android/net/SocketKeepalive.java +++ b/core/java/android/net/SocketKeepalive.java @@ -44,9 +44,11 @@ import java.util.concurrent.Executor; * {@link SocketKeepalive.Callback#onStopped} if the operation was successful or * {@link SocketKeepalive.Callback#onError} if an error occurred. * - * The device SHOULD support keepalive offload. If it does not, it MUST reply with + * For cellular, the device MUST support at least 1 keepalive slot. + * + * For WiFi, the device SHOULD support keepalive offload. If it does not, it MUST reply with * {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload - * request. If it does, it MUST support at least 3 concurrent keepalive slots per transport. + * request. If it does, it MUST support at least 3 concurrent keepalive slots. */ public abstract class SocketKeepalive implements AutoCloseable { static final String TAG = "SocketKeepalive"; From 13a87dccd109d32720f0bec742bdbb1d9e1762f6 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 25 Jun 2019 09:40:54 -0700 Subject: [PATCH 128/130] Only show "Connected" note after opening portal The "Connected" notification would be shown every time a network validates after being identified as a captive portal. This causes issues on networks that have auto-login mechanisms, as a high priority notification would be shown even though the user was not interacting with the phone. The "Connected" notification is intended to confirm to the user that they successfuly logged in (manually), so only show it after the user opens the portal on the network. Bug: 134124044 Test: Flashed, connected to portal: notification shown Opened portal from command line + revalidate: no notification Tests passing with change, failing without Merged-In: I99be7d312d020d242081971c7e522023bbbab072 Merged-In: I7dc1b3a313b255fe89313efb9117bb160efdb533 (cherry picked from commit 0b5a4d862190320d285413b1feb921144fee8420) Change-Id: I67c124cc34f09c2f186706b5cec839f60d00a90a --- .../android/server/ConnectivityService.java | 17 +++++--- .../server/connectivity/NetworkAgentInfo.java | 8 ++-- .../server/ConnectivityServiceTest.java | 42 ++++++++++++++++--- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index e81d1721b2..fc67c38560 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2616,9 +2616,11 @@ public class ConnectivityService extends IConnectivityManager.Stub final boolean valid = ((msg.arg1 & NETWORK_VALIDATION_RESULT_VALID) != 0); final boolean wasValidated = nai.lastValidated; final boolean wasDefault = isDefaultNetwork(nai); - if (nai.everCaptivePortalDetected && !nai.captivePortalLoginNotified - && valid) { - nai.captivePortalLoginNotified = true; + // Only show a connected notification if the network is pending validation + // after the captive portal app was open, and it has now validated. + if (nai.captivePortalValidationPending && valid) { + // User is now logged in, network validated. + nai.captivePortalValidationPending = false; showNetworkNotification(nai, NotificationType.LOGGED_IN); } @@ -2689,9 +2691,6 @@ public class ConnectivityService extends IConnectivityManager.Stub final int oldScore = nai.getCurrentScore(); nai.lastCaptivePortalDetected = visible; nai.everCaptivePortalDetected |= visible; - if (visible) { - nai.captivePortalLoginNotified = false; - } if (nai.lastCaptivePortalDetected && Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) { if (DBG) log("Avoiding captive portal network: " + nai.name()); @@ -3500,6 +3499,12 @@ public class ConnectivityService extends IConnectivityManager.Stub new CaptivePortal(new CaptivePortalImpl(network).asBinder())); appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); + // This runs on a random binder thread, but getNetworkAgentInfoForNetwork is thread-safe, + // and captivePortalValidationPending is volatile. + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai != null) { + nai.captivePortalValidationPending = true; + } Binder.withCleanCallingIdentity(() -> mContext.startActivityAsUser(appIntent, UserHandle.CURRENT)); } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 864a793b8f..5b043799f8 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -155,9 +155,9 @@ public class NetworkAgentInfo implements Comparable { // Whether a captive portal was found during the last network validation attempt. public boolean lastCaptivePortalDetected; - // Indicates the user was notified of a successful captive portal login since a portal was - // last detected. - public boolean captivePortalLoginNotified; + // Indicates the captive portal app was opened to show a login UI to the user, but the network + // has not validated yet. + public volatile boolean captivePortalValidationPending; // Set to true when partial connectivity was detected. public boolean partialConnectivity; @@ -629,7 +629,7 @@ public class NetworkAgentInfo implements Comparable { + "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " + "everCaptivePortalDetected{" + everCaptivePortalDetected + "} " + "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} " - + "captivePortalLoginNotified{" + captivePortalLoginNotified + "} " + + "captivePortalValidationPending{" + captivePortalValidationPending + "} " + "partialConnectivity{" + partialConnectivity + "} " + "acceptPartialConnectivity{" + networkMisc.acceptPartialConnectivity + "} " + "clat{" + clatd + "} " diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 8c024a5a53..73ee7f544b 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -18,6 +18,7 @@ package com.android.server; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; +import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; @@ -80,13 +81,13 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -141,6 +142,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; import android.net.NetworkRequest; import android.net.NetworkSpecifier; +import android.net.NetworkStack; import android.net.NetworkStackClient; import android.net.NetworkState; import android.net.NetworkUtils; @@ -154,6 +156,7 @@ import android.net.shared.NetworkMonitorUtils; import android.net.shared.PrivateDnsConfig; import android.net.util.MultinetworkPolicyTracker; import android.os.Binder; +import android.os.Bundle; import android.os.ConditionVariable; import android.os.Handler; import android.os.HandlerThread; @@ -191,6 +194,7 @@ import com.android.server.connectivity.DefaultNetworkMetrics; import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.Nat464Xlat; +import com.android.server.connectivity.NetworkNotificationManager.NotificationType; import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; @@ -282,6 +286,7 @@ public class ConnectivityServiceTest { @Mock NetworkStackClient mNetworkStack; @Mock PackageManager mPackageManager; @Mock UserManager mUserManager; + @Mock NotificationManager mNotificationManager; private ArgumentCaptor mResolverParamsParcelCaptor = ArgumentCaptor.forClass(ResolverParamsParcel.class); @@ -351,7 +356,7 @@ public class ConnectivityServiceTest { @Override public Object getSystemService(String name) { if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm; - if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class); + if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager; if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack; if (Context.USER_SERVICE.equals(name)) return mUserManager; return super.getSystemService(name); @@ -371,7 +376,17 @@ public class ConnectivityServiceTest { public PackageManager getPackageManager() { return mPackageManager; } - } + + @Override + public void enforceCallingOrSelfPermission(String permission, String message) { + // The mainline permission can only be held if signed with the network stack certificate + // Skip testing for this permission. + if (NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK.equals(permission)) return; + // All other permissions should be held by the test or unnecessary: check as normal to + // make sure the code does not rely on unexpected permissions. + super.enforceCallingOrSelfPermission(permission, message); + } + } public void waitForIdle(int timeoutMsAsInt) { long timeoutMs = timeoutMsAsInt; @@ -2856,6 +2871,9 @@ public class ConnectivityServiceTest { // Expect NET_CAPABILITY_VALIDATED onAvailable callback. validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent); + // Expect no notification to be shown when captive portal disappears by itself + verify(mNotificationManager, never()).notifyAsUser( + anyString(), eq(NotificationType.LOGGED_IN.eventId), any(), any()); // Break network connectivity. // Expect NET_CAPABILITY_VALIDATED onLost callback. @@ -2885,6 +2903,8 @@ public class ConnectivityServiceTest { // Check that calling startCaptivePortalApp does nothing. final int fastTimeoutMs = 100; mCm.startCaptivePortalApp(wifiNetwork); + waitForIdle(); + verify(mWiFiNetworkAgent.mNetworkMonitor, never()).launchCaptivePortalApp(); mServiceContext.expectNoStartActivityIntent(fastTimeoutMs); // Turn into a captive portal. @@ -2895,14 +2915,26 @@ public class ConnectivityServiceTest { // Check that startCaptivePortalApp sends the expected command to NetworkMonitor. mCm.startCaptivePortalApp(wifiNetwork); - verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1)) - .launchCaptivePortalApp(); + waitForIdle(); + verify(mWiFiNetworkAgent.mNetworkMonitor).launchCaptivePortalApp(); + + // NetworkMonitor uses startCaptivePortal(Network, Bundle) (startCaptivePortalAppInternal) + final Bundle testBundle = new Bundle(); + final String testKey = "testkey"; + final String testValue = "testvalue"; + testBundle.putString(testKey, testValue); + mCm.startCaptivePortalApp(wifiNetwork, testBundle); + final Intent signInIntent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS); + assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, signInIntent.getAction()); + assertEquals(testValue, signInIntent.getStringExtra(testKey)); // Report that the captive portal is dismissed, and check that callbacks are fired mWiFiNetworkAgent.setNetworkValid(); mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid()); validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); + verify(mNotificationManager, times(1)).notifyAsUser(anyString(), + eq(NotificationType.LOGGED_IN.eventId), any(), eq(UserHandle.ALL)); mCm.unregisterNetworkCallback(validatedCallback); mCm.unregisterNetworkCallback(captivePortalCallback); From 26f1ab857b17bde6fd0bcf9c1f343b4eeb312357 Mon Sep 17 00:00:00 2001 From: Fedor Kudasov Date: Tue, 9 Jul 2019 14:13:30 +0000 Subject: [PATCH 129/130] Return NonNull and other imports Change-Id: Ia38b13209b45d8228ac02f06663e4dc12be9de60 --- core/java/android/net/NetworkUtils.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index e6472e9c1d..d0f54b4c7f 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -16,10 +16,15 @@ package android.net; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.net.shared.Inet4AddressUtils; import android.os.Build; import android.system.ErrnoException; +import android.system.Os; import android.util.Log; import android.util.Pair; From 8fae993514a3e26befd807de10bc2af2cfc81267 Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Wed, 28 Aug 2019 13:01:05 -0700 Subject: [PATCH 130/130] Add missing nullability annotations. To prepare for enabling MissingNullability Metalava check this CL works on adding missing nullability issues that metalava flags if we tell it to flag new things since API 29. This is not a complete CL, mostly addresses public api and toString/equals for @SystemApi Exempt-From-Owner-Approval: Large scale nullability clean up Bug: 124515653 Test: make -j checkapi Merged-In: I109260842cfc25f06e40694997fcbb4afa02c867 Change-Id: I109260842cfc25f06e40694997fcbb4afa02c867 --- core/java/android/net/StaticIpConfiguration.java | 3 ++- core/java/android/net/apf/ApfCapabilities.java | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java index d6deba5d41..5bc9953e0d 100644 --- a/core/java/android/net/StaticIpConfiguration.java +++ b/core/java/android/net/StaticIpConfiguration.java @@ -236,6 +236,7 @@ public final class StaticIpConfiguration implements Parcelable { return lp; } + @NonNull @Override public String toString() { StringBuffer str = new StringBuffer(); @@ -267,7 +268,7 @@ public final class StaticIpConfiguration implements Parcelable { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (this == obj) return true; if (!(obj instanceof StaticIpConfiguration)) return false; diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java index 4dd2ace59c..b1de74e817 100644 --- a/core/java/android/net/apf/ApfCapabilities.java +++ b/core/java/android/net/apf/ApfCapabilities.java @@ -17,6 +17,7 @@ package android.net.apf; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.res.Resources; @@ -91,6 +92,7 @@ public final class ApfCapabilities implements Parcelable { } }; + @NonNull @Override public String toString() { return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(), @@ -98,7 +100,7 @@ public final class ApfCapabilities implements Parcelable { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (!(obj instanceof ApfCapabilities)) return false; final ApfCapabilities other = (ApfCapabilities) obj; return apfVersionSupported == other.apfVersionSupported