From f3ae766e8e36cc92e1ebf0a31ec2370f3efde2dd Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 18 Mar 2025 19:59:26 +0800 Subject: [PATCH] Add MatchNonThreadLocalNetworks flag in NetworkCapabilities This is for backwards compatibility. Apps targeting V or lower SDK should not see Tethering network agent. This restriction is still disabled to maintain no-op in this change. Will be enabled when introducing ConnectivityService part in the subsequent change. Test: atest CtsNetTestCases:android.net.NetworkCapabilitiesTest \ ConnectivityCoverageTests:android.net.connectivity.com.android.server \ --update-device Bug: 349487600 Change-Id: I99405ab62e82ff4b7fcebffd3a1a31ec6d8962a9 --- .../src/android/net/NetworkCapabilities.java | 60 +++++++++++-- .../android/net/NetworkCapabilitiesTest.java | 90 +++++++++++++++++++ 2 files changed, 145 insertions(+), 5 deletions(-) diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java index c6b62eec07..8355d31a18 100644 --- a/framework/src/android/net/NetworkCapabilities.java +++ b/framework/src/android/net/NetworkCapabilities.java @@ -360,6 +360,8 @@ public final class NetworkCapabilities implements Parcelable { mUnderlyingNetworks = null; mEnterpriseId = 0; mReservationId = RES_ID_UNSET; + // TODO: Change to default disabled when introduce this filtering. + mMatchNonThreadLocalNetworks = true; } /** @@ -395,6 +397,7 @@ public final class NetworkCapabilities implements Parcelable { mUnderlyingNetworks = nc.mUnderlyingNetworks; mEnterpriseId = nc.mEnterpriseId; mReservationId = nc.mReservationId; + mMatchNonThreadLocalNetworks = nc.mMatchNonThreadLocalNetworks; } /** @@ -2236,7 +2239,8 @@ public final class NetworkCapabilities implements Parcelable { && (onlyImmutable || satisfiedBySSID(nc)) && (onlyImmutable || satisfiedByRequestor(nc)) && (onlyImmutable || satisfiedBySubscriptionIds(nc))) - && satisfiedByReservationId(nc); + && satisfiedByReservationId(nc) + && satisfiedByMatchNonThreadLocalNetworks(nc); } /** @@ -2351,7 +2355,8 @@ public final class NetworkCapabilities implements Parcelable { && equalsSubscriptionIds(that) && equalsUnderlyingNetworks(that) && equalsEnterpriseCapabilitiesId(that) - && equalsReservationId(that); + && equalsReservationId(that) + && equalsMatchNonThreadLocalNetworks(that); } @Override @@ -2371,15 +2376,15 @@ public final class NetworkCapabilities implements Parcelable { + Objects.hashCode(mAllowedUids) * 41 + Objects.hashCode(mSSID) * 43 + Objects.hashCode(mTransportInfo) * 47 - + Objects.hashCode(mPrivateDnsBroken) * 53 + + Boolean.hashCode(mPrivateDnsBroken) * 53 + Objects.hashCode(mRequestorUid) * 59 + Objects.hashCode(mRequestorPackageName) * 61 + Arrays.hashCode(mAdministratorUids) * 67 + Objects.hashCode(mSubIds) * 71 + Objects.hashCode(mUnderlyingNetworks) * 73 + mEnterpriseId * 79 - + mReservationId * 83; - + + mReservationId * 83 + + Boolean.hashCode(mMatchNonThreadLocalNetworks) * 89; } @Override @@ -2418,6 +2423,7 @@ public final class NetworkCapabilities implements Parcelable { dest.writeTypedList(mUnderlyingNetworks); dest.writeInt(mEnterpriseId & ALL_VALID_ENTERPRISE_IDS); dest.writeInt(mReservationId); + dest.writeBoolean(mMatchNonThreadLocalNetworks); } public static final @android.annotation.NonNull Creator CREATOR = @@ -2454,8 +2460,10 @@ public final class NetworkCapabilities implements Parcelable { netCap.setUnderlyingNetworks(in.createTypedArrayList(Network.CREATOR)); netCap.mEnterpriseId = in.readInt() & ALL_VALID_ENTERPRISE_IDS; netCap.mReservationId = in.readInt(); + netCap.mMatchNonThreadLocalNetworks = in.readBoolean(); return netCap; } + @Override public NetworkCapabilities[] newArray(int size) { return new NetworkCapabilities[size]; @@ -2561,6 +2569,10 @@ public final class NetworkCapabilities implements Parcelable { sb.append(" ReservationId: ").append(isReservationOffer ? "*" : mReservationId); } + if (mMatchNonThreadLocalNetworks) { + sb.append(" MatchNonThreadLocalNetworks"); + } + sb.append(" UnderlyingNetworks: "); if (mUnderlyingNetworks != null) { sb.append("["); @@ -2945,7 +2957,45 @@ public final class NetworkCapabilities implements Parcelable { return mReservationId == nc.mReservationId; } + /** + * Flag to control whether a NetworkRequest can match non-thread local networks. + * @hide + */ + // TODO: Change to default disabled when introduce this filtering. + private boolean mMatchNonThreadLocalNetworks = true; + /** + * Returns the match non-thread local networks flag. + * + * @hide + */ + public boolean getMatchNonThreadLocalNetworks() { + return mMatchNonThreadLocalNetworks; + } + + /** + * Set the match non-thread local networks flag. + * @hide + */ + public void setMatchNonThreadLocalNetworks(boolean enabled) { + mMatchNonThreadLocalNetworks = enabled; + } + + private boolean equalsMatchNonThreadLocalNetworks(@NonNull NetworkCapabilities nc) { + return mMatchNonThreadLocalNetworks == nc.mMatchNonThreadLocalNetworks; + } + + // If the flag was set, the NetworkRequest can match all local networks. + // Otherwise, it can only see local networks created by Thread. + @SuppressWarnings("FlaggedApi") + private boolean satisfiedByMatchNonThreadLocalNetworks(@NonNull NetworkCapabilities nc) { + // If the network is not a local network, out of scope. + if (!nc.hasCapability(NET_CAPABILITY_LOCAL_NETWORK)) return true; + // If there is no restriction on matching non-thread local networks, return. + if (mMatchNonThreadLocalNetworks) return true; + + return nc.hasTransport(TRANSPORT_THREAD); + } /** * Returns a bitmask of all the applicable redactions (based on the permissions held by the diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java index d69463743d..3fc2af0fb0 100644 --- a/tests/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java @@ -56,6 +56,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; import static android.net.NetworkCapabilities.TRANSPORT_SATELLITE; import static android.net.NetworkCapabilities.TRANSPORT_TEST; +import static android.net.NetworkCapabilities.TRANSPORT_THREAD; import static android.net.NetworkCapabilities.TRANSPORT_USB; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; @@ -1532,4 +1533,93 @@ public class NetworkCapabilitiesTest { nc.setReservationId(43); assertNotEquals(nc, other); } + + @Test + public void testMatchNonThreadLocalNetworks_equals() { + final NetworkCapabilities nc = new NetworkCapabilities(); + nc.setMatchNonThreadLocalNetworks(true); + final NetworkCapabilities other = new NetworkCapabilities(nc); + assertEquals(nc, other); + + nc.setMatchNonThreadLocalNetworks(false); + assertNotEquals(nc, other); + } + + @Test + public void testMatchNonThreadLocalNetworks_enabled() { + doTestMatchNonThreadLocalNetworks(true); + } + + @Test + public void testMatchNonThreadLocalNetworks_disabled() { + doTestMatchNonThreadLocalNetworks(false); + } + + private void doTestMatchNonThreadLocalNetworks(boolean enabled) { + // Setup request NCs. + final NetworkCapabilities noTransportRequestNc = new NetworkCapabilities(); + final NetworkCapabilities threadRequestNc = + new NetworkCapabilities.Builder().addTransportType(TRANSPORT_THREAD).build(); + final NetworkCapabilities wifiRequestNc = + new NetworkCapabilities.Builder().addTransportType(TRANSPORT_WIFI).build(); + final NetworkCapabilities multiTransportRequestNc = + new NetworkCapabilities.Builder().addTransportType( + TRANSPORT_THREAD).addTransportType(TRANSPORT_WIFI).build(); + + // Setup network NCs. + final NetworkCapabilities localNoTransportNc = new NetworkCapabilities.Builder() + .addCapability(NET_CAPABILITY_LOCAL_NETWORK).build(); + final NetworkCapabilities localThreadsNc = new NetworkCapabilities.Builder() + .addCapability(NET_CAPABILITY_LOCAL_NETWORK) + .addTransportType(TRANSPORT_THREAD).build(); + final NetworkCapabilities localWifiNc = new NetworkCapabilities.Builder() + .addCapability(NET_CAPABILITY_LOCAL_NETWORK) + .addTransportType(TRANSPORT_WIFI).build(); + final NetworkCapabilities wanWifiNc = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_WIFI).build(); + + // Mark flags accordingly. + noTransportRequestNc.setMatchNonThreadLocalNetworks(enabled); + threadRequestNc.setMatchNonThreadLocalNetworks(enabled); + wifiRequestNc.setMatchNonThreadLocalNetworks(enabled); + multiTransportRequestNc.setMatchNonThreadLocalNetworks(enabled); + + if (enabled) { + // A request with no specific transport matches all networks. + assertTrue(noTransportRequestNc.satisfiedByNetworkCapabilities(localNoTransportNc)); + assertTrue(noTransportRequestNc.satisfiedByNetworkCapabilities(localWifiNc)); + } else { + // A request with no specific transport only matches thread networks. + assertFalse(noTransportRequestNc.satisfiedByNetworkCapabilities(localNoTransportNc)); + assertFalse(noTransportRequestNc.satisfiedByNetworkCapabilities(localWifiNc)); + } + assertTrue(noTransportRequestNc.satisfiedByNetworkCapabilities(localThreadsNc)); + assertTrue(noTransportRequestNc.satisfiedByNetworkCapabilities(wanWifiNc)); + + // A request with TRANSPORT_THREAD only matches thread networks. + assertFalse(threadRequestNc.satisfiedByNetworkCapabilities(localNoTransportNc)); + assertTrue(threadRequestNc.satisfiedByNetworkCapabilities(localThreadsNc)); + assertFalse(threadRequestNc.satisfiedByNetworkCapabilities(localWifiNc)); + assertFalse(threadRequestNc.satisfiedByNetworkCapabilities(wanWifiNc)); + + assertFalse(multiTransportRequestNc.satisfiedByNetworkCapabilities(localNoTransportNc)); + assertTrue(multiTransportRequestNc.satisfiedByNetworkCapabilities(localThreadsNc)); + assertTrue(multiTransportRequestNc.satisfiedByNetworkCapabilities(wanWifiNc)); + if (enabled) { + assertTrue(multiTransportRequestNc.satisfiedByNetworkCapabilities(localWifiNc)); + } else { + // A request with multiple transports only matches thread networks. + assertFalse(multiTransportRequestNc.satisfiedByNetworkCapabilities(localWifiNc)); + } + + assertFalse(wifiRequestNc.satisfiedByNetworkCapabilities(localNoTransportNc)); + assertFalse(wifiRequestNc.satisfiedByNetworkCapabilities(localThreadsNc)); + assertTrue(wifiRequestNc.satisfiedByNetworkCapabilities(wanWifiNc)); + if (enabled) { + assertTrue(wifiRequestNc.satisfiedByNetworkCapabilities(localWifiNc)); + } else { + // A request without TRANSPORT_THREAD matches nothing. + assertFalse(wifiRequestNc.satisfiedByNetworkCapabilities(localWifiNc)); + } + } }