Merge "Support checking transport types in NetworkTemplate" into main

This commit is contained in:
Treehugger Robot 2025-05-28 22:38:11 -07:00 • committed by Android (Google) Code Review
commit 7c9babc63b
2 changed files with 131 additions and 0 deletions

View file

@ -24,6 +24,12 @@ import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
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_WIFI;
import static android.net.NetworkIdentity.OEM_NONE;
import static android.net.NetworkIdentity.OEM_PAID;
import static android.net.NetworkIdentity.OEM_PRIVATE;
@ -37,6 +43,7 @@ import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.ROAMING_YES;
import static com.android.net.module.util.CollectionUtils.toIntArray;
import static com.android.net.module.util.NetworkCapabilitiesUtils.TYPE_TEST;
import android.annotation.IntDef;
@ -1237,6 +1244,7 @@ public final class NetworkTemplate implements Parcelable {
private void assertRequestableParameters() {
validateWifiNetworkKeys();
validateTransportTypes();
// TODO: Check all the input are legitimate.
}
@ -1249,6 +1257,59 @@ public final class NetworkTemplate implements Parcelable {
}
}
// Validates if transport types are specified (i.e., mTransportTypesBits is not 0),
// they must be consistent with the template's mMatchRule. This means
// the specified transports must include at least one type that is
// deducible or expected for that matchRule.
// For example, if mMatchRule is MATCH_WIFI and transports are specified,
// TRANSPORT_WIFI must be among them.
private void validateTransportTypes() {
assertDeducedTransportTypes(mMatchRule, mTransportTypesBits);
}
/**
* Determines possible transport types for a match rule.
* @return Set of TRANSPORT_* constants.
* @throws IllegalArgumentException for unknown matchRule.
*/
private static Set<Integer> getPossibleTransportsForMatchRule(int matchRule) {
return switch (matchRule) {
case MATCH_MOBILE -> Set.of(TRANSPORT_CELLULAR, TRANSPORT_SATELLITE);
case MATCH_WIFI -> Set.of(TRANSPORT_WIFI);
case MATCH_ETHERNET -> Set.of(TRANSPORT_ETHERNET);
// See NetworkCapabilitiesUtils#deduceTransportTypeForLegacyIdentity.
case MATCH_PROXY, MATCH_BLUETOOTH -> Set.of(TRANSPORT_BLUETOOTH);
// Carrier networks are identified by subscriberId and can be either cellular
// or carrier-provided Wi-Fi.
case MATCH_CARRIER -> Set.of(TRANSPORT_CELLULAR, TRANSPORT_WIFI);
case MATCH_TEST -> Set.of(TRANSPORT_TEST);
default -> throw new IllegalArgumentException(
"Unexpected match rule: " + matchRule);
};
}
/**
* Asserts template's transport types are consistent with its match rule.
* Called during NetworkTemplate construction.
*
* @param matchRule The NetworkTemplate match rule.
* @param transportTypesBits Bitmask of transport types. No-op if 0.
* @throws IllegalArgumentException if transports are inconsistent with the rule.
*/
private static void assertDeducedTransportTypes(int matchRule, long transportTypesBits) {
// No transports specified, nothing to check.
if (transportTypesBits == 0L) return;
Set<Integer> possibleTransportsSet = getPossibleTransportsForMatchRule(matchRule);
final long possibleTransportBitsForMatchRule =
BitUtils.packBits(toIntArray(possibleTransportsSet));
// Template transports must overlap with possible transports for the rule.
if ((transportTypesBits & possibleTransportBitsForMatchRule) == 0L) {
throw new IllegalArgumentException("No deduced transport type: " + matchRule);
}
}
/**
* Builds the instance of the NetworkTemplate.
*

View file

@ -20,6 +20,8 @@ import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
import android.net.NetworkCapabilities.TRANSPORT_SATELLITE
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkCapabilities.TRANSPORT_VPN
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkStats.DEFAULT_NETWORK_ALL
import android.net.NetworkStats.METERED_ALL
@ -32,6 +34,7 @@ import android.net.NetworkTemplate.MATCH_CARRIER
import android.net.NetworkTemplate.MATCH_ETHERNET
import android.net.NetworkTemplate.MATCH_MOBILE
import android.net.NetworkTemplate.MATCH_PROXY
import android.net.NetworkTemplate.MATCH_TEST
import android.net.NetworkTemplate.MATCH_WIFI
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
import android.net.NetworkTemplate.OEM_MANAGED_ALL
@ -50,6 +53,7 @@ import org.junit.runners.JUnit4
private const val TEST_IMSI1 = "imsi"
private const val TEST_WIFI_KEY1 = "wifiKey1"
private const val TEST_WIFI_KEY2 = "wifiKey2"
private const val INVALID_TRANSPORT = 100
@RunWith(JUnit4::class)
@ConnectivityModuleTest
@ -306,6 +310,7 @@ class NetworkTemplateTest {
assertGetSetTransportTypes(MATCH_PROXY, TRANSPORT_BLUETOOTH)
assertGetSetTransportTypes(MATCH_CARRIER, TRANSPORT_CELLULAR)
assertGetSetTransportTypes(MATCH_CARRIER, TRANSPORT_WIFI)
assertGetSetTransportTypes(MATCH_TEST, TRANSPORT_TEST)
}
private fun assertGetSetTransportTypes(matchRule: Int, transport: Int) {
@ -318,4 +323,69 @@ class NetworkTemplateTest {
assertEquals(1, template.transportTypes.size)
assertEquals(transport, template.transportTypes[0])
}
@Test
fun testValidateTransportTypesNoTransportsSetSuccess() {
// Should succeed for any match rule if no transports are explicitly set.
listOf(
MATCH_WIFI,
MATCH_MOBILE,
MATCH_ETHERNET,
MATCH_BLUETOOTH,
MATCH_PROXY,
MATCH_TEST
).forEach { matchRule ->
NetworkTemplate.Builder(matchRule)
.setTransportTypes(intArrayOf()) // Explicitly empty, or just don't call it
.build() // Should not throw
}
NetworkTemplate.Builder(MATCH_CARRIER)
.setSubscriberIds(setOf(TEST_IMSI1))
.setTransportTypes(intArrayOf())
.build() // Should not throw
}
@Test
fun testValidateTransportTypesDeducedTransportPlusCompatibleSuccess() {
NetworkTemplate.Builder(MATCH_WIFI)
.setTransportTypes(intArrayOf(TRANSPORT_WIFI, TRANSPORT_VPN))
.build()
NetworkTemplate.Builder(MATCH_MOBILE)
.setTransportTypes(intArrayOf(TRANSPORT_CELLULAR, TRANSPORT_TEST))
.build()
}
@Test
fun testValidateTransportTypesDeducedTransportMissingThrows() {
assertFailsWith<IllegalArgumentException> {
NetworkTemplate.Builder(MATCH_WIFI)
.setTransportTypes(intArrayOf(TRANSPORT_CELLULAR))
.build()
}
assertFailsWith<IllegalArgumentException> {
NetworkTemplate.Builder(MATCH_MOBILE)
.setTransportTypes(intArrayOf(TRANSPORT_WIFI))
.build()
}
assertFailsWith<IllegalArgumentException> {
NetworkTemplate.Builder(MATCH_ETHERNET)
.setTransportTypes(intArrayOf(TRANSPORT_WIFI))
.build()
}
assertFailsWith<IllegalArgumentException> {
NetworkTemplate.Builder(MATCH_CARRIER)
.setTransportTypes(intArrayOf(TRANSPORT_SATELLITE))
.build()
}
assertFailsWith<IllegalArgumentException> {
NetworkTemplate.Builder(MATCH_TEST)
.setTransportTypes(intArrayOf(TRANSPORT_SATELLITE))
.build()
}
assertFailsWith<IllegalArgumentException> {
NetworkTemplate.Builder(MATCH_TEST)
.setTransportTypes(intArrayOf(INVALID_TRANSPORT))
.build()
}
}
}