From 5ff8baa340df2032477f23b795eae8fae4237d72 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 17 Dec 2019 00:33:18 +0800 Subject: [PATCH 1/5] Remove framework code that has moved to frameworks/libs/net Add srcs to framework and change import path. Remove the codes which are moved to frameworks/libs/net. Bug: 139268426 Bug: 135998869 Bug: 138306002 Bug: 143925787 Test: atest FrameworksNetTests atest FrameworksTelephonyTests ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: Ieb8927f9af7f87a5ae038bd6c7daeb3d70117fef Merged-In: Ieb8927f9af7f87a5ae038bd6c7daeb3d70117fef --- core/java/android/net/LinkProperties.java | 76 ++---------------- core/java/android/net/MacAddress.java | 79 ++----------------- core/java/android/net/NetworkUtils.java | 10 --- core/java/android/net/RouteInfo.java | 17 +--- .../android/server/ConnectivityService.java | 2 +- .../java/android/net/LinkPropertiesTest.java | 2 +- .../net/java/android/net/MacAddressTest.java | 12 +-- 7 files changed, 24 insertions(+), 174 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index d25ee0e69e..732ceb560c 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -21,6 +21,8 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; +import android.net.util.LinkPropertiesUtils; +import android.net.util.LinkPropertiesUtils.CompareResult; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -90,36 +92,6 @@ public final class LinkProperties implements Parcelable { // Indexed by interface name to allow modification and to prevent duplicates being added. private Hashtable mStackedLinks = new Hashtable<>(); - /** - * @hide - */ - public static class CompareResult { - public final List removed = new ArrayList<>(); - public final List added = new ArrayList<>(); - - public CompareResult() {} - - public CompareResult(Collection oldItems, Collection newItems) { - if (oldItems != null) { - removed.addAll(oldItems); - } - if (newItems != null) { - for (T newItem : newItems) { - if (!removed.remove(newItem)) { - added.add(newItem); - } - } - } - } - - @Override - public String toString() { - return "removed=[" + TextUtils.join(",", removed) - + "] added=[" + TextUtils.join(",", added) - + "]"; - } - } - /** * @hide */ @@ -1326,7 +1298,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) { - return TextUtils.equals(getInterfaceName(), target.getInterfaceName()); + return LinkPropertiesUtils.isIdenticalInterfaceName(target, this); } /** @@ -1349,10 +1321,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalAddresses(@NonNull LinkProperties target) { - Collection targetAddresses = target.getAddresses(); - Collection sourceAddresses = getAddresses(); - return (sourceAddresses.size() == targetAddresses.size()) ? - sourceAddresses.containsAll(targetAddresses) : false; + return LinkPropertiesUtils.isIdenticalAddresses(target, this); } /** @@ -1364,15 +1333,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalDnses(@NonNull LinkProperties target) { - Collection targetDnses = target.getDnsServers(); - String targetDomains = target.getDomains(); - if (mDomains == null) { - if (targetDomains != null) return false; - } else { - if (!mDomains.equals(targetDomains)) return false; - } - return (mDnses.size() == targetDnses.size()) ? - mDnses.containsAll(targetDnses) : false; + return LinkPropertiesUtils.isIdenticalDnses(target, this); } /** @@ -1425,9 +1386,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalRoutes(@NonNull LinkProperties target) { - Collection targetRoutes = target.getRoutes(); - return (mRoutes.size() == targetRoutes.size()) ? - mRoutes.containsAll(targetRoutes) : false; + return LinkPropertiesUtils.isIdenticalRoutes(target, this); } /** @@ -1439,8 +1398,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) { - return getHttpProxy() == null ? target.getHttpProxy() == null : - getHttpProxy().equals(target.getHttpProxy()); + return LinkPropertiesUtils.isIdenticalHttpProxy(target, this); } /** @@ -1662,26 +1620,6 @@ public final class LinkProperties implements Parcelable { && isIdenticalCaptivePortalData(target); } - /** - * Compares the addresses in this LinkProperties with another - * LinkProperties, examining only addresses on the base link. - * - * @param target a LinkProperties with the new list of addresses - * @return the differences between the addresses. - * @hide - */ - public @NonNull CompareResult compareAddresses(@Nullable LinkProperties target) { - /* - * Duplicate the LinkAddresses into removed, we will be removing - * address which are common between mLinkAddresses and target - * leaving the addresses that are different. And address which - * are in target but not in mLinkAddresses are placed in the - * addedAddresses. - */ - return new CompareResult<>(mLinkAddresses, - target != null ? target.getLinkAddresses() : null); - } - /** * Compares the DNS addresses in this LinkProperties with another * LinkProperties, examining only DNS addresses on the base link. diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 74c9aac05b..0e10c42e61 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -20,11 +20,11 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.net.util.MacAddressUtils; import android.net.wifi.WifiInfo; import android.os.Parcel; import android.os.Parcelable; -import com.android.internal.util.BitUtils; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -33,7 +33,6 @@ import java.net.Inet6Address; import java.net.UnknownHostException; import java.security.SecureRandom; import java.util.Arrays; -import java.util.Random; /** * Representation of a MAC address. @@ -109,20 +108,12 @@ public final class MacAddress implements Parcelable { if (equals(BROADCAST_ADDRESS)) { return TYPE_BROADCAST; } - if (isMulticastAddress()) { + if ((mAddr & MULTICAST_MASK) != 0) { return TYPE_MULTICAST; } return TYPE_UNICAST; } - /** - * @return true if this MacAddress is a multicast address. - * @hide - */ - public boolean isMulticastAddress() { - return (mAddr & MULTICAST_MASK) != 0; - } - /** * @return true if this MacAddress is a locally assigned address. */ @@ -192,7 +183,7 @@ public final class MacAddress implements Parcelable { * @hide */ public static boolean isMacAddress(byte[] addr) { - return addr != null && addr.length == ETHER_ADDR_LEN; + return MacAddressUtils.isMacAddress(addr); } /** @@ -261,26 +252,11 @@ public final class MacAddress implements Parcelable { } private static byte[] byteAddrFromLongAddr(long addr) { - byte[] bytes = new byte[ETHER_ADDR_LEN]; - int index = ETHER_ADDR_LEN; - while (index-- > 0) { - bytes[index] = (byte) addr; - addr = addr >> 8; - } - return bytes; + return MacAddressUtils.byteAddrFromLongAddr(addr); } private static long longAddrFromByteAddr(byte[] addr) { - Preconditions.checkNotNull(addr); - if (!isMacAddress(addr)) { - throw new IllegalArgumentException( - Arrays.toString(addr) + " was not a valid MAC address"); - } - long longAddr = 0; - for (byte b : addr) { - longAddr = (longAddr << 8) + BitUtils.uint8(b); - } - return longAddr; + return MacAddressUtils.longAddrFromByteAddr(addr); } // Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr)) @@ -350,50 +326,7 @@ public final class MacAddress implements Parcelable { * @hide */ public static @NonNull MacAddress createRandomUnicastAddressWithGoogleBase() { - return createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom()); - } - - /** - * Returns a generated MAC address whose 46 bits, excluding the locally assigned bit and the - * unicast bit, are randomly selected. - * - * The locally assigned bit is always set to 1. The multicast bit is always set to 0. - * - * @return a random locally assigned, unicast MacAddress. - * - * @hide - */ - public static @NonNull MacAddress createRandomUnicastAddress() { - return createRandomUnicastAddress(null, new SecureRandom()); - } - - /** - * Returns a randomly generated MAC address using the given Random object and the same - * OUI values as the given MacAddress. - * - * The locally assigned bit is always set to 1. The multicast bit is always set to 0. - * - * @param base a base MacAddress whose OUI is used for generating the random address. - * If base == null then the OUI will also be randomized. - * @param r a standard Java Random object used for generating the random address. - * @return a random locally assigned MacAddress. - * - * @hide - */ - public static @NonNull MacAddress createRandomUnicastAddress(MacAddress base, Random r) { - long addr; - if (base == null) { - addr = r.nextLong() & VALID_LONG_MASK; - } else { - addr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong()); - } - addr |= LOCALLY_ASSIGNED_MASK; - addr &= ~MULTICAST_MASK; - MacAddress mac = new MacAddress(addr); - if (mac.equals(DEFAULT_MAC_ADDRESS)) { - return createRandomUnicastAddress(base, r); - } - return mac; + return MacAddressUtils.createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom()); } // Convenience function for working around the lack of byte literals. diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 08cc4e24b2..779f7bc91e 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -31,7 +31,6 @@ import android.util.Pair; import java.io.FileDescriptor; import java.math.BigInteger; import java.net.Inet4Address; -import java.net.Inet6Address; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; @@ -312,15 +311,6 @@ public class NetworkUtils { return new Pair(address, prefixLength); } - /** - * Check if IP address type is consistent between two InetAddress. - * @return true if both are the same type. False otherwise. - */ - public static boolean addressTypeMatches(InetAddress left, InetAddress right) { - return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) || - ((left instanceof Inet6Address) && (right instanceof Inet6Address))); - } - /** * Convert a 32 char hex string into a Inet6Address. * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 67bad532cd..2b9e9fe81b 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; +import android.net.util.NetUtils; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -483,21 +484,7 @@ public final class RouteInfo implements Parcelable { @UnsupportedAppUsage @Nullable public static RouteInfo selectBestRoute(Collection routes, InetAddress dest) { - if ((routes == null) || (dest == null)) return null; - - RouteInfo bestRoute = null; - // pick a longest prefix match under same address type - for (RouteInfo route : routes) { - if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { - if ((bestRoute != null) && - (bestRoute.mDestination.getPrefixLength() >= - route.mDestination.getPrefixLength())) { - continue; - } - if (route.matches(dest)) bestRoute = route; - } - } - return bestRoute; + return NetUtils.selectBestRoute(routes, dest); } /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index e98c370149..d834d169a8 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -83,7 +83,6 @@ import android.net.InetAddresses; import android.net.IpMemoryStore; import android.net.IpPrefix; import android.net.LinkProperties; -import android.net.LinkProperties.CompareResult; import android.net.MatchAllNetworkSpecifier; import android.net.NattSocketKeepalive; import android.net.Network; @@ -117,6 +116,7 @@ import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.netlink.InetDiagMessage; import android.net.shared.PrivateDnsConfig; +import android.net.util.LinkPropertiesUtils.CompareResult; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; import android.os.Binder; diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java index 3f311c951c..f25fd4daf8 100644 --- a/tests/net/common/java/android/net/LinkPropertiesTest.java +++ b/tests/net/common/java/android/net/LinkPropertiesTest.java @@ -27,8 +27,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import android.net.LinkProperties.CompareResult; import android.net.LinkProperties.ProvisioningChange; +import android.net.util.LinkPropertiesUtils.CompareResult; import android.system.OsConstants; import android.util.ArraySet; diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java index daf187d015..91c9a2a380 100644 --- a/tests/net/java/android/net/MacAddressTest.java +++ b/tests/net/java/android/net/MacAddressTest.java @@ -22,6 +22,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.net.util.MacAddressUtils; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -122,11 +124,11 @@ public class MacAddressTest { for (MacAddress mac : multicastAddresses) { String msg = mac.toString() + " expected to be a multicast address"; - assertTrue(msg, mac.isMulticastAddress()); + assertTrue(msg, MacAddressUtils.isMulticastAddress(mac)); } for (MacAddress mac : unicastAddresses) { String msg = mac.toString() + " expected not to be a multicast address"; - assertFalse(msg, mac.isMulticastAddress()); + assertFalse(msg, MacAddressUtils.isMulticastAddress(mac)); } } @@ -156,7 +158,7 @@ public class MacAddressTest { public void testMacAddressConversions() { final int iterations = 10000; for (int i = 0; i < iterations; i++) { - MacAddress mac = MacAddress.createRandomUnicastAddress(); + MacAddress mac = MacAddressUtils.createRandomUnicastAddress(); String stringRepr = mac.toString(); byte[] bytesRepr = mac.toByteArray(); @@ -188,7 +190,7 @@ public class MacAddressTest { final String expectedLocalOui = "26:5f:78"; final MacAddress base = MacAddress.fromString(anotherOui + ":0:0:0"); for (int i = 0; i < iterations; i++) { - MacAddress mac = MacAddress.createRandomUnicastAddress(base, r); + MacAddress mac = MacAddressUtils.createRandomUnicastAddress(base, r); String stringRepr = mac.toString(); assertTrue(stringRepr + " expected to be a locally assigned address", @@ -199,7 +201,7 @@ public class MacAddressTest { } for (int i = 0; i < iterations; i++) { - MacAddress mac = MacAddress.createRandomUnicastAddress(); + MacAddress mac = MacAddressUtils.createRandomUnicastAddress(); String stringRepr = mac.toString(); assertTrue(stringRepr + " expected to be a locally assigned address", From aa88bca82bb1b10bb52cb78718ec6d2921b64c7f Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 12 Feb 2020 17:01:59 +0800 Subject: [PATCH 2/5] Update state in NetworkInfo when network resumes State override is only handled when state is changed from CONNECTED to SUSPENDED but not reverse path. Handle both ways for SUSPENDED state. Bug: 148678431 Test: FrameworkNetTests Change-Id: I9333f865d61bbf008fdb8ca162ad17dfdffd1d67 --- .../java/com/android/server/ConnectivityService.java | 9 +++++++++ .../java/com/android/server/ConnectivityServiceTest.java | 2 ++ 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 b3b1722664..d2b1b727ac 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -6952,6 +6952,15 @@ public class ConnectivityService extends IConnectivityManager.Stub // worry about multiple different substates of CONNECTED. newInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, info.getReason(), info.getExtraInfo()); + } else if (!suspended && info.getDetailedState() == NetworkInfo.DetailedState.SUSPENDED) { + // SUSPENDED state is currently only overridden from CONNECTED state. In the case the + // network agent is created, then goes to suspended, then goes out of suspended without + // ever setting connected. Check if network agent is ever connected to update the state. + newInfo.setDetailedState(nai.everConnected + ? NetworkInfo.DetailedState.CONNECTED + : NetworkInfo.DetailedState.CONNECTING, + info.getReason(), + info.getExtraInfo()); } newInfo.setRoaming(!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)); return newInfo; diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 8da1a5b655..4373af9125 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -3171,6 +3171,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent); cellNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); + assertEquals(NetworkInfo.State.SUSPENDED, mCm.getActiveNetworkInfo().getState()); // Register a garden variety default network request. TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback(); @@ -3186,6 +3187,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent); cellNetworkCallback.expectCallback(CallbackEntry.RESUMED, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); + assertEquals(NetworkInfo.State.CONNECTED, mCm.getActiveNetworkInfo().getState()); dfltNetworkCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(dfltNetworkCallback); From 175627fafbb0ce7a4885b0a862213cf1d420cac2 Mon Sep 17 00:00:00 2001 From: Isabelle Taylor Date: Fri, 14 Feb 2020 13:09:16 +0000 Subject: [PATCH 3/5] Revert "Remove framework code that has moved to frameworks/libs/net" Revert "Use createRandomUnicastAddress from MacAddressUtils" Revert "Add net-utils-framework-net to telephony-common" Revert submission 1191997-net-utils-framework-net Reason for revert: Droidcop-triggered revert due to breakage https://android-build.googleplex.com/builds/quarterdeck?branch=git_qt-qpr1-dev-plus-aosp&target=aosp_taimen-userdebug&lkgb=6208131&lkbb=6208273&fkbb=6208273, bug b/149551544 Reverted Changes: Ib1c807d64:Use createRandomUnicastAddress from MacAddressUtil... I9e0f297e0:Add net-utils-framework-net to telephony-common Ieb8927f9a:Remove framework code that has moved to frameworks... Change-Id: I2824f781babd9f7e0bb9df524dadf6b8397dcaa1 --- core/java/android/net/LinkProperties.java | 76 ++++++++++++++++-- core/java/android/net/MacAddress.java | 79 +++++++++++++++++-- core/java/android/net/NetworkUtils.java | 10 +++ core/java/android/net/RouteInfo.java | 17 +++- .../android/server/ConnectivityService.java | 2 +- .../java/android/net/LinkPropertiesTest.java | 2 +- .../net/java/android/net/MacAddressTest.java | 12 ++- 7 files changed, 174 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 732ceb560c..d25ee0e69e 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -21,8 +21,6 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; -import android.net.util.LinkPropertiesUtils; -import android.net.util.LinkPropertiesUtils.CompareResult; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -92,6 +90,36 @@ public final class LinkProperties implements Parcelable { // Indexed by interface name to allow modification and to prevent duplicates being added. private Hashtable mStackedLinks = new Hashtable<>(); + /** + * @hide + */ + public static class CompareResult { + public final List removed = new ArrayList<>(); + public final List added = new ArrayList<>(); + + public CompareResult() {} + + public CompareResult(Collection oldItems, Collection newItems) { + if (oldItems != null) { + removed.addAll(oldItems); + } + if (newItems != null) { + for (T newItem : newItems) { + if (!removed.remove(newItem)) { + added.add(newItem); + } + } + } + } + + @Override + public String toString() { + return "removed=[" + TextUtils.join(",", removed) + + "] added=[" + TextUtils.join(",", added) + + "]"; + } + } + /** * @hide */ @@ -1298,7 +1326,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) { - return LinkPropertiesUtils.isIdenticalInterfaceName(target, this); + return TextUtils.equals(getInterfaceName(), target.getInterfaceName()); } /** @@ -1321,7 +1349,10 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalAddresses(@NonNull LinkProperties target) { - return LinkPropertiesUtils.isIdenticalAddresses(target, this); + Collection targetAddresses = target.getAddresses(); + Collection sourceAddresses = getAddresses(); + return (sourceAddresses.size() == targetAddresses.size()) ? + sourceAddresses.containsAll(targetAddresses) : false; } /** @@ -1333,7 +1364,15 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalDnses(@NonNull LinkProperties target) { - return LinkPropertiesUtils.isIdenticalDnses(target, this); + Collection targetDnses = target.getDnsServers(); + String targetDomains = target.getDomains(); + if (mDomains == null) { + if (targetDomains != null) return false; + } else { + if (!mDomains.equals(targetDomains)) return false; + } + return (mDnses.size() == targetDnses.size()) ? + mDnses.containsAll(targetDnses) : false; } /** @@ -1386,7 +1425,9 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalRoutes(@NonNull LinkProperties target) { - return LinkPropertiesUtils.isIdenticalRoutes(target, this); + Collection targetRoutes = target.getRoutes(); + return (mRoutes.size() == targetRoutes.size()) ? + mRoutes.containsAll(targetRoutes) : false; } /** @@ -1398,7 +1439,8 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) { - return LinkPropertiesUtils.isIdenticalHttpProxy(target, this); + return getHttpProxy() == null ? target.getHttpProxy() == null : + getHttpProxy().equals(target.getHttpProxy()); } /** @@ -1620,6 +1662,26 @@ public final class LinkProperties implements Parcelable { && isIdenticalCaptivePortalData(target); } + /** + * Compares the addresses in this LinkProperties with another + * LinkProperties, examining only addresses on the base link. + * + * @param target a LinkProperties with the new list of addresses + * @return the differences between the addresses. + * @hide + */ + public @NonNull CompareResult compareAddresses(@Nullable LinkProperties target) { + /* + * Duplicate the LinkAddresses into removed, we will be removing + * address which are common between mLinkAddresses and target + * leaving the addresses that are different. And address which + * are in target but not in mLinkAddresses are placed in the + * addedAddresses. + */ + return new CompareResult<>(mLinkAddresses, + target != null ? target.getLinkAddresses() : null); + } + /** * Compares the DNS addresses in this LinkProperties with another * LinkProperties, examining only DNS addresses on the base link. diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 0e10c42e61..74c9aac05b 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -20,11 +20,11 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; -import android.net.util.MacAddressUtils; import android.net.wifi.WifiInfo; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.util.BitUtils; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -33,6 +33,7 @@ import java.net.Inet6Address; import java.net.UnknownHostException; import java.security.SecureRandom; import java.util.Arrays; +import java.util.Random; /** * Representation of a MAC address. @@ -108,12 +109,20 @@ public final class MacAddress implements Parcelable { if (equals(BROADCAST_ADDRESS)) { return TYPE_BROADCAST; } - if ((mAddr & MULTICAST_MASK) != 0) { + if (isMulticastAddress()) { return TYPE_MULTICAST; } return TYPE_UNICAST; } + /** + * @return true if this MacAddress is a multicast address. + * @hide + */ + public boolean isMulticastAddress() { + return (mAddr & MULTICAST_MASK) != 0; + } + /** * @return true if this MacAddress is a locally assigned address. */ @@ -183,7 +192,7 @@ public final class MacAddress implements Parcelable { * @hide */ public static boolean isMacAddress(byte[] addr) { - return MacAddressUtils.isMacAddress(addr); + return addr != null && addr.length == ETHER_ADDR_LEN; } /** @@ -252,11 +261,26 @@ public final class MacAddress implements Parcelable { } private static byte[] byteAddrFromLongAddr(long addr) { - return MacAddressUtils.byteAddrFromLongAddr(addr); + byte[] bytes = new byte[ETHER_ADDR_LEN]; + int index = ETHER_ADDR_LEN; + while (index-- > 0) { + bytes[index] = (byte) addr; + addr = addr >> 8; + } + return bytes; } private static long longAddrFromByteAddr(byte[] addr) { - return MacAddressUtils.longAddrFromByteAddr(addr); + Preconditions.checkNotNull(addr); + if (!isMacAddress(addr)) { + throw new IllegalArgumentException( + Arrays.toString(addr) + " was not a valid MAC address"); + } + long longAddr = 0; + for (byte b : addr) { + longAddr = (longAddr << 8) + BitUtils.uint8(b); + } + return longAddr; } // Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr)) @@ -326,7 +350,50 @@ public final class MacAddress implements Parcelable { * @hide */ public static @NonNull MacAddress createRandomUnicastAddressWithGoogleBase() { - return MacAddressUtils.createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom()); + return createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom()); + } + + /** + * Returns a generated MAC address whose 46 bits, excluding the locally assigned bit and the + * unicast bit, are randomly selected. + * + * The locally assigned bit is always set to 1. The multicast bit is always set to 0. + * + * @return a random locally assigned, unicast MacAddress. + * + * @hide + */ + public static @NonNull MacAddress createRandomUnicastAddress() { + return createRandomUnicastAddress(null, new SecureRandom()); + } + + /** + * Returns a randomly generated MAC address using the given Random object and the same + * OUI values as the given MacAddress. + * + * The locally assigned bit is always set to 1. The multicast bit is always set to 0. + * + * @param base a base MacAddress whose OUI is used for generating the random address. + * If base == null then the OUI will also be randomized. + * @param r a standard Java Random object used for generating the random address. + * @return a random locally assigned MacAddress. + * + * @hide + */ + public static @NonNull MacAddress createRandomUnicastAddress(MacAddress base, Random r) { + long addr; + if (base == null) { + addr = r.nextLong() & VALID_LONG_MASK; + } else { + addr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong()); + } + addr |= LOCALLY_ASSIGNED_MASK; + addr &= ~MULTICAST_MASK; + MacAddress mac = new MacAddress(addr); + if (mac.equals(DEFAULT_MAC_ADDRESS)) { + return createRandomUnicastAddress(base, r); + } + return mac; } // Convenience function for working around the lack of byte literals. diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 779f7bc91e..08cc4e24b2 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -31,6 +31,7 @@ import android.util.Pair; import java.io.FileDescriptor; import java.math.BigInteger; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; @@ -311,6 +312,15 @@ public class NetworkUtils { return new Pair(address, prefixLength); } + /** + * Check if IP address type is consistent between two InetAddress. + * @return true if both are the same type. False otherwise. + */ + public static boolean addressTypeMatches(InetAddress left, InetAddress right) { + return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) || + ((left instanceof Inet6Address) && (right instanceof Inet6Address))); + } + /** * Convert a 32 char hex string into a Inet6Address. * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 2b9e9fe81b..67bad532cd 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -22,7 +22,6 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; -import android.net.util.NetUtils; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -484,7 +483,21 @@ public final class RouteInfo implements Parcelable { @UnsupportedAppUsage @Nullable public static RouteInfo selectBestRoute(Collection routes, InetAddress dest) { - return NetUtils.selectBestRoute(routes, dest); + if ((routes == null) || (dest == null)) return null; + + RouteInfo bestRoute = null; + // pick a longest prefix match under same address type + for (RouteInfo route : routes) { + if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { + if ((bestRoute != null) && + (bestRoute.mDestination.getPrefixLength() >= + route.mDestination.getPrefixLength())) { + continue; + } + if (route.matches(dest)) bestRoute = route; + } + } + return bestRoute; } /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d834d169a8..e98c370149 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -83,6 +83,7 @@ import android.net.InetAddresses; import android.net.IpMemoryStore; import android.net.IpPrefix; import android.net.LinkProperties; +import android.net.LinkProperties.CompareResult; import android.net.MatchAllNetworkSpecifier; import android.net.NattSocketKeepalive; import android.net.Network; @@ -116,7 +117,6 @@ import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.netlink.InetDiagMessage; import android.net.shared.PrivateDnsConfig; -import android.net.util.LinkPropertiesUtils.CompareResult; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; import android.os.Binder; diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java index f25fd4daf8..3f311c951c 100644 --- a/tests/net/common/java/android/net/LinkPropertiesTest.java +++ b/tests/net/common/java/android/net/LinkPropertiesTest.java @@ -27,8 +27,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.net.LinkProperties.CompareResult; import android.net.LinkProperties.ProvisioningChange; -import android.net.util.LinkPropertiesUtils.CompareResult; import android.system.OsConstants; import android.util.ArraySet; diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java index 91c9a2a380..daf187d015 100644 --- a/tests/net/java/android/net/MacAddressTest.java +++ b/tests/net/java/android/net/MacAddressTest.java @@ -22,8 +22,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import android.net.util.MacAddressUtils; - import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -124,11 +122,11 @@ public class MacAddressTest { for (MacAddress mac : multicastAddresses) { String msg = mac.toString() + " expected to be a multicast address"; - assertTrue(msg, MacAddressUtils.isMulticastAddress(mac)); + assertTrue(msg, mac.isMulticastAddress()); } for (MacAddress mac : unicastAddresses) { String msg = mac.toString() + " expected not to be a multicast address"; - assertFalse(msg, MacAddressUtils.isMulticastAddress(mac)); + assertFalse(msg, mac.isMulticastAddress()); } } @@ -158,7 +156,7 @@ public class MacAddressTest { public void testMacAddressConversions() { final int iterations = 10000; for (int i = 0; i < iterations; i++) { - MacAddress mac = MacAddressUtils.createRandomUnicastAddress(); + MacAddress mac = MacAddress.createRandomUnicastAddress(); String stringRepr = mac.toString(); byte[] bytesRepr = mac.toByteArray(); @@ -190,7 +188,7 @@ public class MacAddressTest { final String expectedLocalOui = "26:5f:78"; final MacAddress base = MacAddress.fromString(anotherOui + ":0:0:0"); for (int i = 0; i < iterations; i++) { - MacAddress mac = MacAddressUtils.createRandomUnicastAddress(base, r); + MacAddress mac = MacAddress.createRandomUnicastAddress(base, r); String stringRepr = mac.toString(); assertTrue(stringRepr + " expected to be a locally assigned address", @@ -201,7 +199,7 @@ public class MacAddressTest { } for (int i = 0; i < iterations; i++) { - MacAddress mac = MacAddressUtils.createRandomUnicastAddress(); + MacAddress mac = MacAddress.createRandomUnicastAddress(); String stringRepr = mac.toString(); assertTrue(stringRepr + " expected to be a locally assigned address", From a19115d4828d45336fae5b9e407fe55f16686696 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 13 Feb 2020 16:39:05 +0900 Subject: [PATCH 4/5] [NS D01] Remove candidates that don't satisfy the request. This is exactly equivalent to the previous version (though a bit more expensive) but is useful for followup changes. See [NS D03] to see a sample of how this will be used. Bug: 113554781 Test: FrameworksNetTests Change-Id: I39f3c248bd2f23f7b22bd89d2e1e031653fe9ddb --- .../com/android/server/connectivity/NetworkRanker.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/NetworkRanker.java b/services/core/java/com/android/server/connectivity/NetworkRanker.java index d0aabf95d5..1ae7dc5c36 100644 --- a/services/core/java/com/android/server/connectivity/NetworkRanker.java +++ b/services/core/java/com/android/server/connectivity/NetworkRanker.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.NetworkRequest; +import java.util.ArrayList; import java.util.Collection; /** @@ -31,15 +32,15 @@ public class NetworkRanker { /** * Find the best network satisfying this request among the list of passed networks. */ - // Almost equivalent to Collections.max(nais), but allows returning null if no network - // satisfies the request. @Nullable public NetworkAgentInfo getBestNetwork(@NonNull final NetworkRequest request, @NonNull final Collection nais) { + final ArrayList candidates = new ArrayList<>(nais); + candidates.removeIf(nai -> !nai.satisfies(request)); + NetworkAgentInfo bestNetwork = null; int bestScore = Integer.MIN_VALUE; - for (final NetworkAgentInfo nai : nais) { - if (!nai.satisfies(request)) continue; + for (final NetworkAgentInfo nai : candidates) { if (nai.getCurrentScore() > bestScore) { bestNetwork = nai; bestScore = nai.getCurrentScore(); From 45e11181b4bec93ad87ccf74db3189d0a8540f5d Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 12 Dec 2019 12:57:11 +0900 Subject: [PATCH 5/5] Send LinkProperties update on new capport data When new CaptivePortalData is received from NetworkMonitor, send a LinkProperties updated callback. The updated LinkProperties only contain CaptivePortalData if the receiver has NETWORK_SETTINGS or MAINLINE_NETWORK_STACK permissions, as defined in the current callback code. Test: atest FrameworksNetTests Bug: 139269711 Change-Id: I68595a519171b31792259849efff5f58c43cacd4 --- .../android/server/ConnectivityService.java | 33 ++++++++++ .../server/connectivity/NetworkAgentInfo.java | 5 ++ .../server/ConnectivityServiceTest.java | 61 ++++++++++++++++--- 3 files changed, 91 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1b43fc0fa1..1f027d62c1 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -66,6 +66,7 @@ import android.content.IntentFilter; import android.content.res.Configuration; import android.database.ContentObserver; import android.net.CaptivePortal; +import android.net.CaptivePortalData; import android.net.ConnectionInfo; import android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import android.net.ConnectivityDiagnosticsManager.DataStallReport; @@ -547,6 +548,14 @@ public class ConnectivityService extends IConnectivityManager.Stub */ public static final int EVENT_PROBE_STATUS_CHANGED = 46; + /** + * Event for NetworkMonitor to inform ConnectivityService that captive portal data has changed. + * arg1 = unused + * arg2 = netId + * obj = captive portal data + */ + private static final int EVENT_CAPPORT_DATA_CHANGED = 47; + /** * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification * should be shown. @@ -2817,6 +2826,12 @@ public class ConnectivityService extends IConnectivityManager.Stub updatePrivateDns(nai, (PrivateDnsConfig) msg.obj); break; } + case EVENT_CAPPORT_DATA_CHANGED: { + final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2); + if (nai == null) break; + handleCaptivePortalDataUpdate(nai, (CaptivePortalData) msg.obj); + break; + } } return true; } @@ -2983,6 +2998,13 @@ public class ConnectivityService extends IConnectivityManager.Stub probesCompleted, probesSucceeded, new Integer(mNetId))); } + @Override + public void notifyCaptivePortalDataChanged(CaptivePortalData data) { + mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage( + EVENT_CAPPORT_DATA_CHANGED, + 0, mNetId, data)); + } + @Override public void showProvisioningNotification(String action, String packageName) { final Intent intent = new Intent(action); @@ -3111,6 +3133,13 @@ public class ConnectivityService extends IConnectivityManager.Stub handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); } + private void handleCaptivePortalDataUpdate(@NonNull final NetworkAgentInfo nai, + @Nullable final CaptivePortalData data) { + nai.captivePortalData = data; + // CaptivePortalData will be merged into LinkProperties from NetworkAgentInfo + handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); + } + /** * Updates the linger state from the network requests inside the NAI. * @param nai the agent info to update @@ -5847,6 +5876,10 @@ public class ConnectivityService extends IConnectivityManager.Stub updateWakeOnLan(newLp); + // Captive portal data is obtained from NetworkMonitor and stored in NetworkAgentInfo, + // it is not contained in LinkProperties sent from NetworkAgents so needs to be merged here. + newLp.setCaptivePortalData(networkAgent.captivePortalData); + // TODO - move this check to cover the whole function if (!Objects.equals(newLp, oldLp)) { synchronized (networkAgent) { diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index d30a32041c..58b5cba477 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -21,6 +21,7 @@ import static android.net.NetworkCapabilities.transportNamesOf; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.net.CaptivePortalData; import android.net.IDnsResolver; import android.net.INetd; import android.net.INetworkMonitor; @@ -167,6 +168,10 @@ public class NetworkAgentInfo implements Comparable { // Set to true when partial connectivity was detected. public boolean partialConnectivity; + // Captive portal info of the network, if any. + // Obtained by ConnectivityService and merged into NetworkAgent-provided information. + public CaptivePortalData captivePortalData; + // Networks are lingered when they become unneeded as a result of their NetworkRequests being // satisfied by a higher-scoring network. so as to allow communication to wrap up before the // network is taken down. This usually only happens to the default network. Lingering ends with diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index f40e57fe46..64591a3a87 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -799,6 +799,14 @@ public class ConnectivityServiceTest { mProbesSucceeded = probesSucceeded; } + void notifyCaptivePortalDataChanged(CaptivePortalData data) { + try { + mNmCallbacks.notifyCaptivePortalDataChanged(data); + } catch (RemoteException e) { + throw new AssertionError("This cannot happen", e); + } + } + public String waitForRedirectUrl() { assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS)); return mRedirectUrl; @@ -1845,18 +1853,21 @@ public class ConnectivityServiceTest { final Uri capportUrl = Uri.parse("https://capport.example.com/api"); final CaptivePortalData capportData = new CaptivePortalData.Builder() .setCaptive(true).build(); - newLp.setCaptivePortalApiUrl(capportUrl); - newLp.setCaptivePortalData(capportData); - mWiFiNetworkAgent.sendLinkProperties(newLp); final Uri expectedCapportUrl = sanitized ? null : capportUrl; - final CaptivePortalData expectedCapportData = sanitized ? null : capportData; + newLp.setCaptivePortalApiUrl(capportUrl); + mWiFiNetworkAgent.sendLinkProperties(newLp); callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> - Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()) - && Objects.equals(expectedCapportData, lp.getCaptivePortalData())); + Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl())); defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> - Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()) - && Objects.equals(expectedCapportData, lp.getCaptivePortalData())); + Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl())); + + final CaptivePortalData expectedCapportData = sanitized ? null : capportData; + mWiFiNetworkAgent.notifyCaptivePortalDataChanged(capportData); + callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> + Objects.equals(expectedCapportData, lp.getCaptivePortalData())); + defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> + Objects.equals(expectedCapportData, lp.getCaptivePortalData())); final LinkProperties lp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork()); assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl()); @@ -2810,6 +2821,40 @@ public class ConnectivityServiceTest { assertNoCallbacks(captivePortalCallback, validatedCallback); } + @Test + public void testCaptivePortalApi() throws Exception { + mServiceContext.setPermission( + android.Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED); + + final TestNetworkCallback captivePortalCallback = new TestNetworkCallback(); + final NetworkRequest captivePortalRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build(); + mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback); + + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + final String redirectUrl = "http://example.com/firstPath"; + + mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */); + captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + + final CaptivePortalData testData = new CaptivePortalData.Builder() + .setUserPortalUrl(Uri.parse(redirectUrl)) + .setBytesRemaining(12345L) + .build(); + + mWiFiNetworkAgent.notifyCaptivePortalDataChanged(testData); + + captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, + lp -> testData.equals(lp.getCaptivePortalData())); + + final LinkProperties newLps = new LinkProperties(); + newLps.setMtu(1234); + mWiFiNetworkAgent.sendLinkProperties(newLps); + // CaptivePortalData is not lost and unchanged when LPs are received from the NetworkAgent + captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, + lp -> testData.equals(lp.getCaptivePortalData()) && lp.getMtu() == 1234); + } + private NetworkRequest.Builder newWifiRequestBuilder() { return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI); }