Creating interface name to index tracking for Bpf Maps.

Adding mechanism to track interaface name to interface index, this map
would be used by BpfNetMaps for storing interface index.

Bug: 400681214
Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.server.connectivity.InterfaceTrackerTest
Test: atest ConnectivityCoverageTests:android.net.connectivity.com.android.server.BpfNetMapsTest
Change-Id: I2a65cac908d9c4d10714e3fe26be20322d4a1db3
This commit is contained in:
Sarup Dalwani 2025-03-05 15:43:22 +00:00
commit 53ecd95072
9 changed files with 357 additions and 45 deletions

View file

@ -21,7 +21,6 @@ import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.UID_ALL;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.net.NetworkStats;
import android.net.UnderlyingNetworkInfo;
@ -31,6 +30,7 @@ import android.os.SystemClock;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.BpfNetMaps;
import com.android.server.connectivity.InterfaceTracker;
import java.io.IOException;
import java.net.ProtocolException;
@ -108,7 +108,7 @@ public class NetworkStatsFactory {
/** Create a new {@link BpfNetMaps}. */
public BpfNetMaps createBpfNetMaps(@NonNull Context ctx) {
return new BpfNetMaps(ctx);
return new BpfNetMaps(ctx, new InterfaceTracker(ctx));
}
}

View file

@ -49,6 +49,8 @@ import static com.android.server.connectivity.NetworkPermissions.TRAFFIC_PERMISS
import static com.android.server.connectivity.NetworkPermissions.TRAFFIC_PERMISSION_UNINSTALLED;
import static com.android.server.connectivity.NetworkPermissions.TRAFFIC_PERMISSION_UPDATE_DEVICE_STATS;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.StatsManager;
import android.content.Context;
import android.net.BpfNetMapsUtils;
@ -85,12 +87,14 @@ import com.android.net.module.util.bpf.CookieTagMapValue;
import com.android.net.module.util.bpf.IngressDiscardKey;
import com.android.net.module.util.bpf.IngressDiscardValue;
import com.android.net.module.util.bpf.LocalNetAccessKey;
import com.android.server.connectivity.InterfaceTracker;
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
@ -142,6 +146,7 @@ public class BpfNetMaps {
Pair.create(TRAFFIC_PERMISSION_INTERNET, "PERMISSION_INTERNET"),
Pair.create(TRAFFIC_PERMISSION_UPDATE_DEVICE_STATS, "PERMISSION_UPDATE_DEVICE_STATS")
);
private final InterfaceTracker mInterfaceTracker;
/**
* Set configurationMap for test.
@ -423,23 +428,27 @@ public class BpfNetMaps {
/** Constructor used after T that doesn't need to use netd anymore. */
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public BpfNetMaps(final Context context) {
this(context, null);
public BpfNetMaps(final Context context, @NonNull final InterfaceTracker interfaceTracker) {
this(context, null, interfaceTracker);
if (!SdkLevel.isAtLeastT()) throw new IllegalArgumentException("BpfNetMaps need to use netd before T");
}
public BpfNetMaps(final Context context, final INetd netd) {
this(context, netd, new Dependencies());
public BpfNetMaps(final Context context, final INetd netd, @NonNull final InterfaceTracker
interfaceTracker) {
this(context, netd, new Dependencies(), interfaceTracker);
}
@VisibleForTesting
public BpfNetMaps(final Context context, final INetd netd, final Dependencies deps) {
public BpfNetMaps(final Context context, final INetd netd, final Dependencies deps,
@NonNull final InterfaceTracker interfaceTracker) {
Objects.requireNonNull(interfaceTracker);
if (SdkLevel.isAtLeastT()) {
ensureInitialized(context);
}
mNetd = netd;
mDeps = deps;
mInterfaceTracker = interfaceTracker;
}
private void maybeThrow(final int err, final String msg) {
@ -902,7 +911,7 @@ public class BpfNetMaps {
* @param isAllowed is the local network call allowed or blocked.
*/
@RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT)
public void addLocalNetAccess(final int lpmBitlen, final String iface,
public void addLocalNetAccess(final int lpmBitlen, @Nullable final String iface,
final InetAddress address, final int protocol, final int remotePort,
final boolean isAllowed) {
throwIfPre25Q2("addLocalNetAccess is not available on pre-B devices");
@ -910,7 +919,7 @@ public class BpfNetMaps {
if (iface == null) {
ifIndex = 0;
} else {
ifIndex = mDeps.getIfIndex(iface);
ifIndex = mInterfaceTracker.getInterfaceIndex(iface);
}
if (ifIndex == 0) {
Log.e(TAG, "Failed to get if index, skip addLocalNetAccess for " + address
@ -937,14 +946,14 @@ public class BpfNetMaps {
* @param remotePort src/dst port for ingress/egress
*/
@RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT)
public void removeLocalNetAccess(final int lpmBitlen, final String iface,
public void removeLocalNetAccess(final int lpmBitlen, @Nullable final String iface,
final InetAddress address, final int protocol, final int remotePort) {
throwIfPre25Q2("removeLocalNetAccess is not available on pre-B devices");
final int ifIndex;
if (iface == null) {
ifIndex = 0;
} else {
ifIndex = mDeps.getIfIndex(iface);
ifIndex = mInterfaceTracker.getInterfaceIndex(iface);
}
if (ifIndex == 0) {
Log.e(TAG, "Failed to get if index, skip removeLocalNetAccess for " + address
@ -973,14 +982,14 @@ public class BpfNetMaps {
* is not local network or if configuration is allowed like local dns servers.
*/
@RequiresApi(Build.VERSION_CODES.CUR_DEVELOPMENT)
public boolean getLocalNetAccess(final int lpmBitlen, final String iface,
public boolean getLocalNetAccess(final int lpmBitlen, @Nullable final String iface,
final InetAddress address, final int protocol, final int remotePort) {
throwIfPre25Q2("getLocalNetAccess is not available on pre-B devices");
final int ifIndex;
if (iface == null) {
ifIndex = 0;
} else {
ifIndex = mDeps.getIfIndex(iface);
ifIndex = mInterfaceTracker.getInterfaceIndex(iface);
}
if (ifIndex == 0) {
Log.e(TAG, "Failed to get if index, returning default from getLocalNetAccess for "

View file

@ -365,6 +365,7 @@ import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
import com.android.server.connectivity.DscpPolicyTracker;
import com.android.server.connectivity.FullScore;
import com.android.server.connectivity.InterfaceTracker;
import com.android.server.connectivity.InvalidTagException;
import com.android.server.connectivity.KeepaliveResourceUtil;
import com.android.server.connectivity.KeepaliveTracker;
@ -577,6 +578,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private final NetworkStatsManager mStatsManager;
private final NetworkPolicyManager mPolicyManager;
private final BpfNetMaps mBpfNetMaps;
private final InterfaceTracker mInterfaceTracker;
/**
* TestNetworkService (lazily) created upon first usage. Locked to prevent creation of multiple
@ -1662,8 +1664,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* @param netd a netd binder
* @return BpfNetMaps implementation.
*/
public BpfNetMaps getBpfNetMaps(Context context, INetd netd) {
return new BpfNetMaps(context, netd);
public BpfNetMaps getBpfNetMaps(Context context, INetd netd,
InterfaceTracker interfaceTracker) {
return new BpfNetMaps(context, netd, interfaceTracker);
}
/**
* Get the InterfaceTracker implementation to use in ConnectivityService.
* @return InterfaceTracker implementation.
*/
public InterfaceTracker getInterfaceTracker(Context context) {
return new InterfaceTracker(context);
}
/**
@ -1886,7 +1897,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mWakeUpMask = mask;
mNetd = netd;
mBpfNetMaps = mDeps.getBpfNetMaps(mContext, netd);
mInterfaceTracker = mDeps.getInterfaceTracker(mContext);
mBpfNetMaps = mDeps.getBpfNetMaps(mContext, netd, mInterfaceTracker);
mHandlerThread = mDeps.makeHandlerThread("ConnectivityServiceThread");
mPermissionMonitorDeps = mPermDeps;
mPermissionMonitor =
@ -9605,8 +9617,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
updateIngressToVpnAddressFiltering(newLp, oldLp, networkAgent);
updateLocalNetworkAddresses(newLp, oldLp);
updateMtu(newLp, oldLp);
// TODO - figure out what to do for clat
// for (LinkProperties lp : newLp.getStackedLinks()) {
@ -9769,16 +9779,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
wakeupModifyInterface(iface, nai, true);
mDeps.reportNetworkInterfaceForTransports(mContext, iface,
nai.networkCapabilities.getTransportTypes());
mInterfaceTracker.addInterface(iface);
} catch (Exception e) {
logw("Exception adding interface: " + e);
}
}
}
// The local network addresses needs to be updated before interfaces are removed because
// modifying bpf map local_net_access requires mapping interface name to index.
updateLocalNetworkAddresses(newLp, oldLp);
for (final String iface : interfaceDiff.removed) {
try {
if (DBG) log("Removing iface " + iface + " from network " + netId);
wakeupModifyInterface(iface, nai, false);
mRoutingCoordinatorService.removeInterfaceFromNetwork(netId, iface);
mInterfaceTracker.removeInterface(iface);
} catch (Exception e) {
loge("Exception removing interface: " + e);
}

View file

@ -0,0 +1,123 @@
/*
* Copyright (C) 2025 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.Nullable;
import android.content.Context;
import android.system.Os;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.BpfNetMaps;
import java.util.Map;
/**
* InterfaceTracker is responsible for providing interface mapping and tracking.
* @hide
*/
public class InterfaceTracker {
static {
if (BpfNetMaps.isAtLeast25Q2()) {
System.loadLibrary("service-connectivity");
}
}
private static final String TAG = "InterfaceTracker";
private final Dependencies mDeps;
private final Map<String, Integer> mInterfaceMap;
public InterfaceTracker(final Context context) {
this(context, new Dependencies());
}
@VisibleForTesting
public InterfaceTracker(final Context context, final Dependencies deps) {
this.mInterfaceMap = new ArrayMap<>();
this.mDeps = deps;
}
/**
* To add interface to tracking
* @param interfaceName name of interface added.
*/
public void addInterface(@Nullable final String interfaceName) {
final int interfaceIndex;
if (interfaceName == null) {
interfaceIndex = 0;
} else {
interfaceIndex = mDeps.getIfIndex(interfaceName);
}
if (interfaceIndex == 0) {
Log.e(TAG, "Failed to get interface index for " + interfaceName);
return;
}
synchronized (mInterfaceMap) {
mInterfaceMap.put(interfaceName, interfaceIndex);
}
}
/**
* To remove interface from tracking
* @param interfaceName name of interface removed.
* @return true if the value was present and now removed.
*/
public boolean removeInterface(@Nullable final String interfaceName) {
if (interfaceName == null) return false;
synchronized (mInterfaceMap) {
return mInterfaceMap.remove(interfaceName) != null;
}
}
/**
* Get interface index from interface name.
* @param interfaceName name of interface
* @return interface index for given interface name or 0 if interface is not found.
*/
public int getInterfaceIndex(@Nullable final String interfaceName) {
final int interfaceIndex;
if (interfaceName != null) {
synchronized (mInterfaceMap) {
interfaceIndex = mInterfaceMap.getOrDefault(interfaceName, 0);
}
} else {
interfaceIndex = 0;
}
return interfaceIndex;
}
/**
* Dependencies of InterfaceTracker, for injection in tests.
*/
@VisibleForTesting
public static class Dependencies {
/**
* Get interface index.
*/
public int getIfIndex(final String ifName) {
return Os.if_nametoindex(ifName);
}
/**
* Get interface name
*/
public String getIfName(final int ifIndex) {
return Os.if_indextoname(ifIndex);
}
}
}

View file

@ -55,11 +55,11 @@ import com.android.net.module.util.BpfUtils
import com.android.networkstack.apishim.TelephonyManagerShimImpl
import com.android.server.BpfNetMaps
import com.android.server.ConnectivityService
import com.android.server.L2capNetworkProvider
import com.android.server.NetworkAgentWrapper
import com.android.server.TestNetIdManager
import com.android.server.connectivity.CarrierPrivilegeAuthenticator
import com.android.server.connectivity.ConnectivityResources
import com.android.server.connectivity.InterfaceTracker
import com.android.server.connectivity.MockableSystemProperties
import com.android.server.connectivity.MultinetworkPolicyTracker
import com.android.server.connectivity.PermissionMonitor
@ -114,6 +114,8 @@ class ConnectivityServiceIntegrationTest {
@Mock
private lateinit var netd: INetd
@Mock
private lateinit var interfaceTracker: InterfaceTracker
@Mock
private lateinit var dnsResolver: IDnsResolver
@Mock
private lateinit var systemConfigManager: SystemConfigManager
@ -140,11 +142,15 @@ class ConnectivityServiceIntegrationTest {
private val realContext get() = InstrumentationRegistry.getInstrumentation().context
private val httpProbeUrl get() =
realContext.getResources().getString(com.android.server.net.integrationtests.R.string
.config_captive_portal_http_url)
realContext.getResources().getString(
com.android.server.net.integrationtests.R.string
.config_captive_portal_http_url
)
private val httpsProbeUrl get() =
realContext.getResources().getString(com.android.server.net.integrationtests.R.string
.config_captive_portal_https_url)
realContext.getResources().getString(
com.android.server.net.integrationtests.R.string
.config_captive_portal_https_url
)
private class InstrumentationServiceConnection : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
@ -166,12 +172,19 @@ class ConnectivityServiceIntegrationTest {
fun setUpClass() {
val intent = Intent(realContext, NetworkStackInstrumentationService::class.java)
intent.action = INetworkStackInstrumentation::class.qualifiedName
assertTrue(realContext.bindService(intent, InstrumentationServiceConnection(),
BIND_AUTO_CREATE or BIND_IMPORTANT),
"Error binding to instrumentation service")
assertTrue(bindingCondition.block(SERVICE_BIND_TIMEOUT_MS),
assertTrue(
realContext.bindService(
intent,
InstrumentationServiceConnection(),
BIND_AUTO_CREATE or BIND_IMPORTANT
),
"Error binding to instrumentation service"
)
assertTrue(
bindingCondition.block(SERVICE_BIND_TIMEOUT_MS),
"Timed out binding to instrumentation service " +
"after $SERVICE_BIND_TIMEOUT_MS ms")
"after $SERVICE_BIND_TIMEOUT_MS ms"
)
}
}
@ -201,7 +214,8 @@ class ConnectivityServiceIntegrationTest {
// We don't test the actual notification value strings, so just return an empty array.
// It doesn't matter what the values are as long as it's not null.
doReturn(emptyArray<String>()).`when`(resources).getStringArray(
R.array.network_switch_type_name)
R.array.network_switch_type_name
)
doReturn(1).`when`(resources).getInteger(R.integer.config_networkAvoidBadWifi)
doReturn(R.array.config_networkSupportedKeepaliveCount).`when`(resources)
.getIdentifier(eq("config_networkSupportedKeepaliveCount"), eq("array"), any())
@ -223,7 +237,13 @@ class ConnectivityServiceIntegrationTest {
}
private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
context, dnsResolver, log, netd, deps, PermissionMonitorDependencies())
context,
dnsResolver,
log,
netd,
deps,
PermissionMonitorDependencies()
)
private inner class TestDependencies : ConnectivityService.Dependencies() {
override fun getNetworkStack() = networkStackClient
@ -231,7 +251,11 @@ class ConnectivityServiceIntegrationTest {
mock(ProxyTracker::class.java)
override fun getSystemProperties() = mock(MockableSystemProperties::class.java)
override fun makeNetIdManager() = TestNetIdManager()
override fun getBpfNetMaps(context: Context?, netd: INetd?) = mock(BpfNetMaps::class.java)
override fun getBpfNetMaps(
context: Context?,
netd: INetd?,
interfaceTracker: InterfaceTracker?
) = mock(BpfNetMaps::class.java)
.also {
doReturn(PERMISSION_INTERNET).`when`(it).getNetPermForUid(anyInt())
}
@ -241,13 +265,17 @@ class ConnectivityServiceIntegrationTest {
c: Context,
h: Handler,
r: Runnable
) = MultinetworkPolicyTracker(c, h, r,
) = MultinetworkPolicyTracker(
c,
h,
r,
object : MultinetworkPolicyTracker.Dependencies() {
override fun getResourcesForActiveSubId(
connResources: ConnectivityResources,
activeSubId: Int
) = resources
})
}
)
override fun makeHandlerThread(tag: String): HandlerThread =
super.makeHandlerThread(tag).also { handlerThreads.add(it) }
@ -259,13 +287,18 @@ class ConnectivityServiceIntegrationTest {
listener: BiConsumer<Int, Int>,
handler: Handler
): CarrierPrivilegeAuthenticator {
return CarrierPrivilegeAuthenticator(context,
return CarrierPrivilegeAuthenticator(
context,
object : CarrierPrivilegeAuthenticator.Dependencies() {
override fun makeHandlerThread(): HandlerThread =
super.makeHandlerThread().also { handlerThreads.add(it) }
},
tm, TelephonyManagerShimImpl.newInstance(tm),
requestRestrictedWifiEnabled, listener, handler)
tm,
TelephonyManagerShimImpl.newInstance(tm),
requestRestrictedWifiEnabled,
listener,
handler
)
}
override fun makeSatelliteAccessController(
@ -273,7 +306,8 @@ class ConnectivityServiceIntegrationTest {
updateSatellitePreferredUid: Consumer<MutableSet<Int>>?,
connectivityServiceInternalHandler: Handler
): SatelliteAccessController? = mock(
SatelliteAccessController::class.java)
SatelliteAccessController::class.java
)
override fun makeL2capNetworkProvider(context: Context) = null
}
@ -305,8 +339,12 @@ class ConnectivityServiceIntegrationTest {
nsInstrumentation.addHttpResponse(HttpResponse(httpProbeUrl, responseCode = 204))
nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))
val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), null /* ncTemplate */,
context)
val na = NetworkAgentWrapper(
TRANSPORT_CELLULAR,
LinkProperties(),
null /* ncTemplate */,
context
)
networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
na.addCapability(NET_CAPABILITY_INTERNET)
@ -344,7 +382,8 @@ class ConnectivityServiceIntegrationTest {
| "user-portal-url": "https://login.capport.android.com",
| "venue-info-url": "https://venueinfo.capport.android.com"
|}
""".trimMargin()))
""".trimMargin()
))
// Tests will fail if a non-mocked query is received: mock the HTTPS probe, but not the
// HTTP probe as it should not be sent.
@ -398,8 +437,10 @@ class ConnectivityServiceIntegrationTest {
BpfUtils.BPF_CGROUP_INET_EGRESS,
BpfUtils.BPF_CGROUP_INET_SOCK_CREATE
).forEach {
val ret = SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
"cmd connectivity bpf-get-cgroup-program-id $it").trim()
val ret = SystemUtil.runShellCommand(
InstrumentationRegistry.getInstrumentation(),
"cmd connectivity bpf-get-cgroup-program-id $it"
).trim()
assertTrue(Integer.parseInt(ret) > 0, "Unexpected output $ret for type $it")
}

View file

@ -109,6 +109,7 @@ import com.android.net.module.util.bpf.CookieTagMapValue;
import com.android.net.module.util.bpf.IngressDiscardKey;
import com.android.net.module.util.bpf.IngressDiscardValue;
import com.android.net.module.util.bpf.LocalNetAccessKey;
import com.android.server.connectivity.InterfaceTracker;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@ -170,6 +171,8 @@ public final class BpfNetMapsTest {
@Mock INetd mNetd;
@Mock BpfNetMaps.Dependencies mDeps;
@Mock Context mContext;
@Mock InterfaceTracker mInterfaceTracker;
private final IBpfMap<S32, U32> mConfigurationMap = new TestBpfMap<>(S32.class, U32.class);
private final IBpfMap<S32, UidOwnerValue> mUidOwnerMap =
new TestBpfMap<>(S32.class, UidOwnerValue.class);
@ -188,6 +191,7 @@ public final class BpfNetMapsTest {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
doReturn(TEST_IF_INDEX).when(mDeps).getIfIndex(TEST_IF_NAME);
doReturn(TEST_IF_INDEX).when(mInterfaceTracker).getInterfaceIndex(TEST_IF_NAME);
doReturn(TEST_IF_NAME).when(mDeps).getIfName(TEST_IF_INDEX);
doReturn(0).when(mDeps).synchronizeKernelRCU();
BpfNetMaps.setConfigurationMapForTest(mConfigurationMap);
@ -202,7 +206,7 @@ public final class BpfNetMapsTest {
BpfNetMaps.setDataSaverEnabledMapForTest(mDataSaverEnabledMap);
mDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, new U8(DATA_SAVER_DISABLED));
BpfNetMaps.setIngressDiscardMapForTest(mIngressDiscardMap);
mBpfNetMaps = new BpfNetMaps(mContext, mNetd, mDeps);
mBpfNetMaps = new BpfNetMaps(mContext, mNetd, mDeps, mInterfaceTracker);
}
@Test

View file

@ -413,6 +413,7 @@ import com.android.server.connectivity.CarrierPrivilegeAuthenticator;
import com.android.server.connectivity.ClatCoordinator;
import com.android.server.connectivity.ConnectivityFlags;
import com.android.server.connectivity.ConnectivityResources;
import com.android.server.connectivity.InterfaceTracker;
import com.android.server.connectivity.KeepaliveTracker;
import com.android.server.connectivity.MultinetworkPolicyTracker;
import com.android.server.connectivity.MultinetworkPolicyTrackerTestDependencies;
@ -2262,7 +2263,8 @@ public class ConnectivityServiceTest {
}
@Override
public BpfNetMaps getBpfNetMaps(Context context, INetd netd) {
public BpfNetMaps getBpfNetMaps(Context context, INetd netd,
InterfaceTracker interfaceTracker) {
return mBpfNetMaps;
}

View file

@ -0,0 +1,110 @@
/*
* Copyright (C) 2025 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 static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doReturn;
import android.content.Context;
import android.os.Build;
import androidx.test.filters.SmallTest;
import com.android.testutils.ConnectivityModuleTest;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
@ConnectivityModuleTest
public class InterfaceTrackerTest {
private static final String TAG = "InterfaceTrackerTest";
private static final String TEST_IF_NAME = "wlan10";
private static final String TEST_INCORRECT_IF_NAME = "wlan20";
private static final int TEST_IF_INDEX = 7;
@Rule
public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
private InterfaceTracker mInterfaceTracker;
@Mock Context mContext;
@Mock InterfaceTracker.Dependencies mDeps;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
doReturn(TEST_IF_INDEX).when(mDeps).getIfIndex(TEST_IF_NAME);
mInterfaceTracker = new InterfaceTracker(mContext, mDeps);
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void testAddingInterface_InterfaceNameIndexMappingAdded() {
mInterfaceTracker.addInterface(TEST_IF_NAME);
assertEquals(TEST_IF_INDEX, mInterfaceTracker.getInterfaceIndex(TEST_IF_NAME));
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void testAddingNullInterface_InterfaceNameIndexMappingNotAdded() {
mInterfaceTracker.addInterface(null);
assertEquals(0, mInterfaceTracker.getInterfaceIndex(TEST_IF_NAME));
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void testAddingIncorrectInterface_InterfaceNameIndexMappingNotAdded() {
mInterfaceTracker.addInterface(TEST_INCORRECT_IF_NAME);
assertEquals(0, mInterfaceTracker.getInterfaceIndex(TEST_INCORRECT_IF_NAME));
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void testRemovingInterface_InterfaceNameIndexMappingRemoved() {
mInterfaceTracker.addInterface(TEST_IF_NAME);
assertEquals(TEST_IF_INDEX, mInterfaceTracker.getInterfaceIndex(TEST_IF_NAME));
mInterfaceTracker.removeInterface(TEST_IF_NAME);
assertEquals(0, mInterfaceTracker.getInterfaceIndex(TEST_IF_NAME));
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void testRemovingNullInterface_InterfaceNameIndexMappingNotRemoved() {
mInterfaceTracker.addInterface(TEST_IF_NAME);
mInterfaceTracker.removeInterface(null);
assertEquals(TEST_IF_INDEX, mInterfaceTracker.getInterfaceIndex(TEST_IF_NAME));
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public void testRemovingIncorrectInterface_InterfaceNameIndexMappingNotRemoved() {
mInterfaceTracker.addInterface(TEST_IF_NAME);
mInterfaceTracker.removeInterface(TEST_INCORRECT_IF_NAME);
assertEquals(TEST_IF_INDEX, mInterfaceTracker.getInterfaceIndex(TEST_IF_NAME));
}
}

View file

@ -68,6 +68,7 @@ import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker
import com.android.server.connectivity.CarrierPrivilegeAuthenticator
import com.android.server.connectivity.ClatCoordinator
import com.android.server.connectivity.ConnectivityFlags
import com.android.server.connectivity.InterfaceTracker
import com.android.server.connectivity.MulticastRoutingCoordinatorService
import com.android.server.connectivity.MultinetworkPolicyTracker
import com.android.server.connectivity.MultinetworkPolicyTrackerTestDependencies
@ -193,6 +194,7 @@ open class CSTest {
val connResources = makeMockConnResources(sysResources, packageManager)
val netd = mock<INetd>()
val interfaceTracker = mock<InterfaceTracker>()
val bpfNetMaps = mock<BpfNetMaps>().also {
doReturn(PERMISSION_INTERNET).`when`(it).getNetPermForUid(anyInt())
}
@ -279,7 +281,11 @@ open class CSTest {
inner class CSDeps : ConnectivityService.Dependencies() {
override fun getResources(ctx: Context) = connResources
override fun getBpfNetMaps(context: Context, netd: INetd) = this@CSTest.bpfNetMaps
override fun getBpfNetMaps(
context: Context,
netd: INetd,
interfaceTracker: InterfaceTracker
) = this@CSTest.bpfNetMaps
override fun getClatCoordinator(netd: INetd?) = this@CSTest.clatCoordinator
override fun getNetworkStack() = this@CSTest.networkStack