Merge "[Thread] add configuration methods in ThreadNetworkControllerWrapper" into main
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index 7a6df88..f60d7a1 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -70,13 +70,13 @@
import com.android.internal.util.State;
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.InterfaceParams;
+import com.android.net.module.util.IIpv4PrefixRequest;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.RoutingCoordinatorManager;
import com.android.net.module.util.SharedLog;
import com.android.net.module.util.SyncStateMachine.StateInfo;
import com.android.net.module.util.ip.InterfaceController;
import com.android.networkstack.tethering.BpfCoordinator;
-import com.android.networkstack.tethering.PrivateAddressCoordinator;
import com.android.networkstack.tethering.TetheringConfiguration;
import com.android.networkstack.tethering.metrics.TetheringMetrics;
import com.android.networkstack.tethering.util.InterfaceSet;
@@ -242,9 +242,10 @@
private final BpfCoordinator mBpfCoordinator;
@NonNull
private final RoutingCoordinatorManager mRoutingCoordinator;
+ @NonNull
+ private final IIpv4PrefixRequest mIpv4PrefixRequest;
private final Callback mCallback;
private final InterfaceController mInterfaceCtrl;
- private final PrivateAddressCoordinator mPrivateAddressCoordinator;
private final String mIfaceName;
private final int mInterfaceType;
@@ -301,7 +302,7 @@
String ifaceName, Handler handler, int interfaceType, SharedLog log,
INetd netd, @NonNull BpfCoordinator bpfCoordinator,
RoutingCoordinatorManager routingCoordinatorManager, Callback callback,
- TetheringConfiguration config, PrivateAddressCoordinator addressCoordinator,
+ TetheringConfiguration config,
TetheringMetrics tetheringMetrics, Dependencies deps) {
super(ifaceName, USE_SYNC_SM ? null : handler.getLooper());
mHandler = handler;
@@ -309,6 +310,12 @@
mNetd = netd;
mBpfCoordinator = bpfCoordinator;
mRoutingCoordinator = routingCoordinatorManager;
+ mIpv4PrefixRequest = new IIpv4PrefixRequest.Stub() {
+ @Override
+ public void onIpv4PrefixConflict(IpPrefix ipPrefix) throws RemoteException {
+ sendMessage(CMD_NOTIFY_PREFIX_CONFLICT);
+ }
+ };
mCallback = callback;
mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog);
mIfaceName = ifaceName;
@@ -317,7 +324,6 @@
mUsingLegacyDhcp = config.useLegacyDhcpServer();
mP2pLeasesSubnetPrefixLength = config.getP2pLeasesSubnetPrefixLength();
mIsWifiP2pDedicatedIpEnabled = config.shouldEnableWifiP2pDedicatedIp();
- mPrivateAddressCoordinator = addressCoordinator;
mDeps = deps;
mTetheringMetrics = tetheringMetrics;
resetLinkProperties();
@@ -395,6 +401,11 @@
return mInterfaceParams;
}
+ @VisibleForTesting
+ public IIpv4PrefixRequest getIpv4PrefixRequest() {
+ return mIpv4PrefixRequest;
+ }
+
/**
* Get the latest list of DHCP leases that was reported. Must be called on the IpServer looper
* thread.
@@ -643,7 +654,7 @@
// NOTE: All of configureIPv4() will be refactored out of existence
// into calls to InterfaceController, shared with startIPv4().
mInterfaceCtrl.clearIPv4Address();
- mPrivateAddressCoordinator.releaseDownstream(this);
+ mRoutingCoordinator.releaseDownstream(mIpv4PrefixRequest);
mBpfCoordinator.tetherOffloadClientClear(this);
mIpv4Address = null;
mStaticIpv4ServerAddr = null;
@@ -714,7 +725,8 @@
if (shouldUseWifiP2pDedicatedIp()) return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
- return mPrivateAddressCoordinator.requestDownstreamAddress(this, scope, useLastAddress);
+ return mRoutingCoordinator.requestDownstreamAddress(mInterfaceType, scope, useLastAddress,
+ mIpv4PrefixRequest);
}
private boolean startIPv6() {
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 13b8004..df255f3 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -253,7 +253,6 @@
private final TetheringNotificationUpdater mNotificationUpdater;
private final UserManager mUserManager;
private final BpfCoordinator mBpfCoordinator;
- private final PrivateAddressCoordinator mPrivateAddressCoordinator;
private final TetheringMetrics mTetheringMetrics;
private final WearableConnectionManager mWearableConnectionManager;
private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
@@ -359,7 +358,6 @@
// Load tethering configuration.
updateConfiguration();
mConfig.readEnableSyncSM(mContext);
- mPrivateAddressCoordinator = mDeps.makePrivateAddressCoordinator(mContext);
// Must be initialized after tethering configuration is loaded because BpfCoordinator
// constructor needs to use the configuration.
@@ -2001,11 +1999,11 @@
final UpstreamNetworkState ns = (UpstreamNetworkState) o;
switch (arg1) {
case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
- mPrivateAddressCoordinator.updateUpstreamPrefix(
+ mRoutingCoordinator.updateUpstreamPrefix(
ns.linkProperties, ns.networkCapabilities, ns.network);
break;
case UpstreamNetworkMonitor.EVENT_ON_LOST:
- mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network);
+ mRoutingCoordinator.removeUpstreamPrefix(ns.network);
break;
}
@@ -2075,7 +2073,7 @@
return;
}
- mPrivateAddressCoordinator.maybeRemoveDeprecatedUpstreams();
+ mRoutingCoordinator.maybeRemoveDeprecatedUpstreams();
mUpstreamNetworkMonitor.startObserveAllNetworks();
// TODO: De-duplicate with updateUpstreamWanted() below.
@@ -2663,11 +2661,6 @@
dumpBpf(pw);
- pw.println("Private address coordinator:");
- pw.increaseIndent();
- mPrivateAddressCoordinator.dump(pw);
- pw.decreaseIndent();
-
if (mWearableConnectionManager != null) {
pw.println("WearableConnectionManager:");
pw.increaseIndent();
@@ -2821,8 +2814,7 @@
mLog.i("adding IpServer for: " + iface);
final TetherState tetherState = new TetherState(
new IpServer(iface, mHandler, interfaceType, mLog, mNetd, mBpfCoordinator,
- mRoutingCoordinator, new ControlCallback(), mConfig,
- mPrivateAddressCoordinator, mTetheringMetrics,
+ mRoutingCoordinator, new ControlCallback(), mConfig, mTetheringMetrics,
mDeps.makeIpServerDependencies()), isNcm);
mTetherStates.put(iface, tetherState);
tetherState.ipServer.start();
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
index cc878d5..a4823ca 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
@@ -36,6 +36,7 @@
import androidx.annotation.RequiresApi;
import com.android.modules.utils.build.SdkLevel;
+import com.android.net.module.util.PrivateAddressCoordinator;
import com.android.net.module.util.RoutingCoordinatorManager;
import com.android.net.module.util.RoutingCoordinatorService;
import com.android.net.module.util.SharedLog;
@@ -136,7 +137,10 @@
public RoutingCoordinatorManager getRoutingCoordinator(Context context, SharedLog log) {
IBinder binder;
if (!SdkLevel.isAtLeastS()) {
- binder = new RoutingCoordinatorService(getINetd(context, log));
+ final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
+ binder =
+ new RoutingCoordinatorService(
+ getINetd(context, log), cm::getAllNetworks, context);
} else {
binder = ConnectivityInternalApiUtil.getRoutingCoordinator(context);
}
@@ -175,14 +179,6 @@
}
/**
- * Make PrivateAddressCoordinator to be used by Tethering.
- */
- public PrivateAddressCoordinator makePrivateAddressCoordinator(Context ctx) {
- final ConnectivityManager cm = ctx.getSystemService(ConnectivityManager.class);
- return new PrivateAddressCoordinator(cm::getAllNetworks, ctx);
- }
-
- /**
* Make BluetoothPanShim object to enable/disable bluetooth tethering.
*
* TODO: use BluetoothPan directly when mainline module is built with API 32.
diff --git a/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
index 423b9b8..01f3af9 100644
--- a/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
+++ b/Tethering/tests/integration/base/android/net/EthernetTetheringTestBase.java
@@ -70,7 +70,7 @@
import com.android.net.module.util.structs.FragmentHeader;
import com.android.net.module.util.structs.Ipv6Header;
import com.android.testutils.HandlerUtils;
-import com.android.testutils.TapPacketReader;
+import com.android.testutils.PollPacketReader;
import com.android.testutils.TestNetworkTracker;
import org.junit.After;
@@ -158,10 +158,10 @@
protected TetheredInterfaceRequester mTetheredInterfaceRequester;
// Late initialization in initTetheringTester().
- private TapPacketReader mUpstreamReader;
+ private PollPacketReader mUpstreamReader;
private TestNetworkTracker mUpstreamTracker;
private TestNetworkInterface mDownstreamIface;
- private TapPacketReader mDownstreamReader;
+ private PollPacketReader mDownstreamReader;
private MyTetheringEventCallback mTetheringEventCallback;
public Context getContext() {
@@ -187,10 +187,10 @@
return runAsShell(NETWORK_SETTINGS, TETHER_PRIVILEGED, () -> sTm.isTetheringSupported());
}
- protected void maybeStopTapPacketReader(final TapPacketReader tapPacketReader)
+ protected void maybeStopTapPacketReader(final PollPacketReader tapPacketReader)
throws Exception {
if (tapPacketReader != null) {
- TapPacketReader reader = tapPacketReader;
+ PollPacketReader reader = tapPacketReader;
mHandler.post(() -> reader.stop());
}
}
@@ -228,7 +228,7 @@
});
}
if (mUpstreamReader != null) {
- TapPacketReader reader = mUpstreamReader;
+ PollPacketReader reader = mUpstreamReader;
mHandler.post(() -> reader.stop());
mUpstreamReader = null;
}
@@ -291,7 +291,7 @@
});
}
- protected static void waitForRouterAdvertisement(TapPacketReader reader, String iface,
+ protected static void waitForRouterAdvertisement(PollPacketReader reader, String iface,
long timeoutMs) {
final long deadline = SystemClock.uptimeMillis() + timeoutMs;
do {
@@ -574,13 +574,13 @@
return nif.getIndex();
}
- protected TapPacketReader makePacketReader(final TestNetworkInterface iface) throws Exception {
+ protected PollPacketReader makePacketReader(final TestNetworkInterface iface) throws Exception {
FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
return makePacketReader(fd, getMTU(iface));
}
- protected TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
- final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
+ protected PollPacketReader makePacketReader(FileDescriptor fd, int mtu) {
+ final PollPacketReader reader = new PollPacketReader(mHandler, fd, mtu);
mHandler.post(() -> reader.start());
HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
return reader;
diff --git a/Tethering/tests/integration/base/android/net/TetheringTester.java b/Tethering/tests/integration/base/android/net/TetheringTester.java
index b152b4c..fb94eed 100644
--- a/Tethering/tests/integration/base/android/net/TetheringTester.java
+++ b/Tethering/tests/integration/base/android/net/TetheringTester.java
@@ -84,7 +84,7 @@
import com.android.net.module.util.structs.RaHeader;
import com.android.net.module.util.structs.TcpHeader;
import com.android.net.module.util.structs.UdpHeader;
-import com.android.testutils.TapPacketReader;
+import com.android.testutils.PollPacketReader;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -157,14 +157,14 @@
public static final String DHCP_HOSTNAME = "testhostname";
private final ArrayMap<MacAddress, TetheredDevice> mTetheredDevices;
- private final TapPacketReader mDownstreamReader;
- private final TapPacketReader mUpstreamReader;
+ private final PollPacketReader mDownstreamReader;
+ private final PollPacketReader mUpstreamReader;
- public TetheringTester(TapPacketReader downstream) {
+ public TetheringTester(PollPacketReader downstream) {
this(downstream, null);
}
- public TetheringTester(TapPacketReader downstream, TapPacketReader upstream) {
+ public TetheringTester(PollPacketReader downstream, PollPacketReader upstream) {
if (downstream == null) fail("Downstream reader could not be NULL");
mDownstreamReader = downstream;
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 32b2f3e..1bbea94 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -80,7 +80,7 @@
import com.android.testutils.DeviceInfoUtils;
import com.android.testutils.DumpTestUtils;
import com.android.testutils.NetworkStackModuleTest;
-import com.android.testutils.TapPacketReader;
+import com.android.testutils.PollPacketReader;
import org.junit.After;
import org.junit.Rule;
@@ -213,7 +213,7 @@
TestNetworkInterface downstreamIface = null;
MyTetheringEventCallback tetheringEventCallback = null;
- TapPacketReader downstreamReader = null;
+ PollPacketReader downstreamReader = null;
try {
downstreamIface = createTestInterface();
@@ -253,7 +253,7 @@
TestNetworkInterface downstreamIface = null;
MyTetheringEventCallback tetheringEventCallback = null;
- TapPacketReader downstreamReader = null;
+ PollPacketReader downstreamReader = null;
try {
downstreamIface = createTestInterface();
@@ -283,7 +283,7 @@
TestNetworkInterface downstreamIface = null;
MyTetheringEventCallback tetheringEventCallback = null;
- TapPacketReader downstreamReader = null;
+ PollPacketReader downstreamReader = null;
try {
downstreamIface = createTestInterface();
@@ -357,7 +357,7 @@
TestNetworkInterface downstreamIface = null;
MyTetheringEventCallback tetheringEventCallback = null;
- TapPacketReader downstreamReader = null;
+ PollPacketReader downstreamReader = null;
try {
downstreamIface = createTestInterface();
@@ -423,7 +423,7 @@
// client, which is not possible in this test.
}
- private void checkTetheredClientCallbacks(final TapPacketReader packetReader,
+ private void checkTetheredClientCallbacks(final PollPacketReader packetReader,
final MyTetheringEventCallback tetheringEventCallback) throws Exception {
// Create a fake client.
byte[] clientMacAddr = new byte[6];
diff --git a/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
index ebf09ed..0f3f5bb 100644
--- a/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
+++ b/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
@@ -43,7 +43,7 @@
import com.android.networkstack.tethering.util.TetheringUtils;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRunner;
-import com.android.testutils.TapPacketReader;
+import com.android.testutils.PollPacketReader;
import com.android.testutils.TapPacketReaderRule;
import org.junit.After;
@@ -75,7 +75,7 @@
private InterfaceParams mUpstreamParams, mTetheredParams;
private HandlerThread mHandlerThread;
private Handler mHandler;
- private TapPacketReader mUpstreamPacketReader, mTetheredPacketReader;
+ private PollPacketReader mUpstreamPacketReader, mTetheredPacketReader;
private static INetd sNetd;
@@ -219,7 +219,7 @@
}
// TODO: change to assert.
- private boolean waitForPacket(ByteBuffer packet, TapPacketReader reader) {
+ private boolean waitForPacket(ByteBuffer packet, PollPacketReader reader) {
byte[] p;
while ((p = reader.popPacket(PACKET_TIMEOUT_MS)) != null) {
@@ -247,7 +247,7 @@
}
private void receivePacketAndMaybeExpectForwarded(boolean expectForwarded,
- ByteBuffer in, TapPacketReader inReader, ByteBuffer out, TapPacketReader outReader)
+ ByteBuffer in, PollPacketReader inReader, ByteBuffer out, PollPacketReader outReader)
throws IOException {
inReader.sendResponse(in);
@@ -271,13 +271,13 @@
assertEquals(msg, expectForwarded, waitForPacket(out, outReader));
}
- private void receivePacketAndExpectForwarded(ByteBuffer in, TapPacketReader inReader,
- ByteBuffer out, TapPacketReader outReader) throws IOException {
+ private void receivePacketAndExpectForwarded(ByteBuffer in, PollPacketReader inReader,
+ ByteBuffer out, PollPacketReader outReader) throws IOException {
receivePacketAndMaybeExpectForwarded(true, in, inReader, out, outReader);
}
- private void receivePacketAndExpectNotForwarded(ByteBuffer in, TapPacketReader inReader,
- ByteBuffer out, TapPacketReader outReader) throws IOException {
+ private void receivePacketAndExpectNotForwarded(ByteBuffer in, PollPacketReader inReader,
+ ByteBuffer out, PollPacketReader outReader) throws IOException {
receivePacketAndMaybeExpectForwarded(false, in, inReader, out, outReader);
}
diff --git a/Tethering/tests/privileged/src/android/net/ip/RouterAdvertisementDaemonTest.java b/Tethering/tests/privileged/src/android/net/ip/RouterAdvertisementDaemonTest.java
index 90ceaa1..7cc8c74 100644
--- a/Tethering/tests/privileged/src/android/net/ip/RouterAdvertisementDaemonTest.java
+++ b/Tethering/tests/privileged/src/android/net/ip/RouterAdvertisementDaemonTest.java
@@ -64,7 +64,7 @@
import com.android.net.module.util.structs.PrefixInformationOption;
import com.android.net.module.util.structs.RaHeader;
import com.android.net.module.util.structs.RdnssOption;
-import com.android.testutils.TapPacketReader;
+import com.android.testutils.PollPacketReader;
import com.android.testutils.TapPacketReaderRule;
import org.junit.After;
@@ -93,7 +93,7 @@
private InterfaceParams mTetheredParams;
private HandlerThread mHandlerThread;
private Handler mHandler;
- private TapPacketReader mTetheredPacketReader;
+ private PollPacketReader mTetheredPacketReader;
private RouterAdvertisementDaemon mRaDaemon;
private static INetd sNetd;
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index f7834a3..8f5e6c4 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -89,13 +89,10 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.InterfaceParams;
import com.android.net.module.util.RoutingCoordinatorManager;
-import com.android.net.module.util.SdkUtil.LateSdk;
import com.android.net.module.util.SharedLog;
import com.android.networkstack.tethering.BpfCoordinator;
-import com.android.networkstack.tethering.PrivateAddressCoordinator;
import com.android.networkstack.tethering.TetheringConfiguration;
import com.android.networkstack.tethering.metrics.TetheringMetrics;
import com.android.networkstack.tethering.util.InterfaceSet;
@@ -175,7 +172,6 @@
@Mock private DadProxy mDadProxy;
@Mock private RouterAdvertisementDaemon mRaDaemon;
@Mock private IpServer.Dependencies mDependencies;
- @Mock private PrivateAddressCoordinator mAddressCoordinator;
@Mock private RoutingCoordinatorManager mRoutingCoordinatorManager;
@Mock private NetworkStatsManager mStatsManager;
@Mock private TetheringConfiguration mTetherConfig;
@@ -261,9 +257,9 @@
verify(mBpfCoordinator).updateIpv6UpstreamInterface(
mIpServer, interfaceParams.index, upstreamPrefixes);
}
- reset(mNetd, mBpfCoordinator, mCallback, mAddressCoordinator);
- when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(),
- anyBoolean())).thenReturn(mTestAddress);
+ reset(mNetd, mBpfCoordinator, mCallback, mRoutingCoordinatorManager);
+ when(mRoutingCoordinatorManager.requestDownstreamAddress(anyInt(), anyInt(),
+ anyBoolean(), any())).thenReturn(mTestAddress);
}
@SuppressWarnings("DoNotCall") // Ignore warning for synchronous to call to Thread.run()
@@ -284,8 +280,8 @@
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
- when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(),
- anyBoolean())).thenReturn(mTestAddress);
+ when(mRoutingCoordinatorManager.requestDownstreamAddress(anyInt(), anyInt(),
+ anyBoolean(), any())).thenReturn(mTestAddress);
when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(DEFAULT_USING_BPF_OFFLOAD);
when(mTetherConfig.useLegacyDhcpServer()).thenReturn(false /* default value */);
@@ -297,7 +293,7 @@
mLooper = new TestLooper();
mHandler = new Handler(mLooper.getLooper());
return new IpServer(IFACE_NAME, mHandler, interfaceType, mSharedLog, mNetd, mBpfCoordinator,
- mRoutingCoordinatorManager, mCallback, mTetherConfig, mAddressCoordinator,
+ mRoutingCoordinatorManager, mCallback, mTetherConfig,
mTetheringMetrics, mDependencies);
}
@@ -349,10 +345,14 @@
initStateMachine(TETHERING_BLUETOOTH);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
+ InOrder inOrder = inOrder(mCallback, mNetd, mRoutingCoordinatorManager);
if (isAtLeastT()) {
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(),
- eq(CONNECTIVITY_SCOPE_GLOBAL), eq(true));
+ inOrder.verify(mRoutingCoordinatorManager)
+ .requestDownstreamAddress(
+ eq(TETHERING_BLUETOOTH),
+ eq(CONNECTIVITY_SCOPE_GLOBAL),
+ eq(true),
+ any());
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
}
@@ -373,7 +373,7 @@
initTetheredStateMachine(TETHERING_BLUETOOTH, null);
dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
- InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
+ InOrder inOrder = inOrder(mCallback, mNetd, mRoutingCoordinatorManager);
inOrder.verify(mNetd).tetherApplyDnsInterfaces();
inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME);
inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
@@ -384,7 +384,7 @@
argThat(cfg -> assertContainsFlag(cfg.flags, IF_STATE_DOWN)));
}
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> cfg.flags.length == 0));
- inOrder.verify(mAddressCoordinator).releaseDownstream(any());
+ inOrder.verify(mRoutingCoordinatorManager).releaseDownstream(any());
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
@@ -392,7 +392,7 @@
verify(mTetheringMetrics).updateErrorCode(eq(TETHERING_BLUETOOTH),
eq(TETHER_ERROR_NO_ERROR));
verify(mTetheringMetrics).sendReport(eq(TETHERING_BLUETOOTH));
- verifyNoMoreInteractions(mNetd, mCallback, mAddressCoordinator);
+ verifyNoMoreInteractions(mNetd, mCallback, mRoutingCoordinatorManager);
}
@Test
@@ -400,9 +400,9 @@
initStateMachine(TETHERING_USB);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
- InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(),
- eq(CONNECTIVITY_SCOPE_GLOBAL), eq(true));
+ InOrder inOrder = inOrder(mCallback, mNetd, mRoutingCoordinatorManager);
+ inOrder.verify(mRoutingCoordinatorManager).requestDownstreamAddress(anyInt(),
+ eq(CONNECTIVITY_SCOPE_GLOBAL), eq(true), any());
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
@@ -414,7 +414,7 @@
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), mLinkPropertiesCaptor.capture());
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
- verifyNoMoreInteractions(mNetd, mCallback, mAddressCoordinator);
+ verifyNoMoreInteractions(mNetd, mCallback, mRoutingCoordinatorManager);
}
@Test
@@ -422,9 +422,9 @@
initStateMachine(TETHERING_WIFI_P2P);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
- InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(),
- eq(CONNECTIVITY_SCOPE_LOCAL), eq(true));
+ InOrder inOrder = inOrder(mCallback, mNetd, mRoutingCoordinatorManager);
+ inOrder.verify(mRoutingCoordinatorManager).requestDownstreamAddress(anyInt(),
+ eq(CONNECTIVITY_SCOPE_LOCAL), eq(true), any());
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
@@ -436,7 +436,7 @@
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), mLinkPropertiesCaptor.capture());
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
- verifyNoMoreInteractions(mNetd, mCallback, mAddressCoordinator);
+ verifyNoMoreInteractions(mNetd, mCallback, mRoutingCoordinatorManager);
}
@Test
@@ -445,11 +445,11 @@
true /* shouldEnableWifiP2pDedicatedIp */);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
- InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
+ InOrder inOrder = inOrder(mCallback, mNetd, mRoutingCoordinatorManager);
// When using WiFi P2p dedicated IP, the IpServer just picks the IP address without
- // requesting for it at PrivateAddressCoordinator.
- inOrder.verify(mAddressCoordinator, never()).requestDownstreamAddress(any(), anyInt(),
- anyBoolean());
+ // requesting for it at RoutingCoordinatorManager.
+ inOrder.verify(mRoutingCoordinatorManager, never())
+ .requestDownstreamAddress(anyInt(), anyInt(), anyBoolean(), any());
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
@@ -463,7 +463,7 @@
assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
assertEquals(List.of(new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS)),
mLinkPropertiesCaptor.getValue().getLinkAddresses());
- verifyNoMoreInteractions(mNetd, mCallback, mAddressCoordinator);
+ verifyNoMoreInteractions(mNetd, mCallback, mRoutingCoordinatorManager);
}
@Test
@@ -569,15 +569,9 @@
initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
clearInvocations(
- mNetd, mCallback, mAddressCoordinator, mBpfCoordinator, mRoutingCoordinatorManager);
+ mNetd, mCallback, mBpfCoordinator, mRoutingCoordinatorManager);
dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
- InOrder inOrder =
- inOrder(
- mNetd,
- mCallback,
- mAddressCoordinator,
- mBpfCoordinator,
- mRoutingCoordinatorManager);
+ InOrder inOrder = inOrder(mNetd, mCallback, mBpfCoordinator, mRoutingCoordinatorManager);
inOrder.verify(mBpfCoordinator).maybeDetachProgram(IFACE_NAME, UPSTREAM_IFACE);
inOrder.verify(mRoutingCoordinatorManager)
.removeInterfaceForward(IFACE_NAME, UPSTREAM_IFACE);
@@ -592,15 +586,14 @@
inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
inOrder.verify(mNetd, times(isAtLeastT() ? 2 : 1)).interfaceSetCfg(
argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
- inOrder.verify(mAddressCoordinator).releaseDownstream(any());
+ inOrder.verify(mRoutingCoordinatorManager).releaseDownstream(any());
inOrder.verify(mBpfCoordinator).tetherOffloadClientClear(mIpServer);
inOrder.verify(mBpfCoordinator).removeIpServer(mIpServer);
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(
eq(mIpServer), any(LinkProperties.class));
- verifyNoMoreInteractions(
- mNetd, mCallback, mAddressCoordinator, mBpfCoordinator, mRoutingCoordinatorManager);
+ verifyNoMoreInteractions(mNetd, mCallback, mRoutingCoordinatorManager, mBpfCoordinator);
}
@Test
@@ -737,9 +730,9 @@
final ArgumentCaptor<LinkProperties> lpCaptor =
ArgumentCaptor.forClass(LinkProperties.class);
- InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(),
- eq(CONNECTIVITY_SCOPE_LOCAL), eq(true));
+ InOrder inOrder = inOrder(mNetd, mCallback, mRoutingCoordinatorManager);
+ inOrder.verify(mRoutingCoordinatorManager).requestDownstreamAddress(anyInt(),
+ eq(CONNECTIVITY_SCOPE_LOCAL), eq(true), any());
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
// One for ipv4 route, one for ipv6 link local route.
inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
@@ -747,18 +740,18 @@
inOrder.verify(mCallback).updateInterfaceState(
mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR);
inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture());
- verifyNoMoreInteractions(mCallback, mAddressCoordinator);
+ verifyNoMoreInteractions(mCallback, mRoutingCoordinatorManager);
// Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals
// onNewPrefixRequest callback.
final LinkAddress newAddress = new LinkAddress("192.168.100.125/24");
- when(mAddressCoordinator.requestDownstreamAddress(any(), anyInt(),
- anyBoolean())).thenReturn(newAddress);
+ when(mRoutingCoordinatorManager.requestDownstreamAddress(anyInt(), anyInt(),
+ anyBoolean(), any())).thenReturn(newAddress);
eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24"));
mLooper.dispatchAll();
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(),
- eq(CONNECTIVITY_SCOPE_LOCAL), eq(false));
+ inOrder.verify(mRoutingCoordinatorManager).requestDownstreamAddress(anyInt(),
+ eq(CONNECTIVITY_SCOPE_LOCAL), eq(false), any());
inOrder.verify(mNetd).tetherApplyDnsInterfaces();
inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture());
verifyNoMoreInteractions(mCallback);
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index bff1fda..1ab5766 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -24,8 +24,9 @@
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+import static android.net.ip.IpServer.CMD_NOTIFY_PREFIX_CONFLICT;
-import static com.android.networkstack.tethering.PrivateAddressCoordinator.TETHER_FORCE_RANDOM_PREFIX_BASE_SELECTION;
+import static com.android.net.module.util.PrivateAddressCoordinator.TETHER_FORCE_RANDOM_PREFIX_BASE_SELECTION;
import static com.android.networkstack.tethering.util.PrefixUtils.asIpPrefix;
import static org.junit.Assert.assertEquals;
@@ -34,6 +35,9 @@
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.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -47,10 +51,14 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.ip.IpServer;
+import android.os.IBinder;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.net.module.util.IIpv4PrefixRequest;
+import com.android.net.module.util.PrivateAddressCoordinator;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -92,12 +100,26 @@
new IpPrefix("172.16.0.0/12"),
new IpPrefix("10.0.0.0/8")));
+ private void setUpIpServer(IpServer ipServer, int interfaceType) throws Exception {
+ when(ipServer.interfaceType()).thenReturn(interfaceType);
+ final IIpv4PrefixRequest request = mock(IIpv4PrefixRequest.class);
+ when(ipServer.getIpv4PrefixRequest()).thenReturn(request);
+ when(request.asBinder()).thenReturn(mock(IBinder.class));
+ doAnswer(
+ invocation -> {
+ ipServer.sendMessage(CMD_NOTIFY_PREFIX_CONFLICT);
+ return null;
+ })
+ .when(request)
+ .onIpv4PrefixConflict(any());
+ }
+
private void setUpIpServers() throws Exception {
- when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
- when(mEthernetIpServer.interfaceType()).thenReturn(TETHERING_ETHERNET);
- when(mHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI);
- when(mLocalHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI);
- when(mWifiP2pIpServer.interfaceType()).thenReturn(TETHERING_WIFI_P2P);
+ setUpIpServer(mUsbIpServer, TETHERING_USB);
+ setUpIpServer(mEthernetIpServer, TETHERING_ETHERNET);
+ setUpIpServer(mHotspotIpServer, TETHERING_WIFI);
+ setUpIpServer(mLocalHotspotIpServer, TETHERING_WIFI);
+ setUpIpServer(mWifiP2pIpServer, TETHERING_WIFI_P2P);
}
@Before
@@ -112,14 +134,22 @@
spy(new PrivateAddressCoordinator(mConnectivityMgr::getAllNetworks, mDeps));
}
- private LinkAddress requestDownstreamAddress(final IpServer ipServer, int scope,
- boolean useLastAddress) {
- final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- ipServer, scope, useLastAddress);
+ private LinkAddress requestDownstreamAddress(
+ final IpServer ipServer, int scope, boolean useLastAddress) throws Exception {
+ final LinkAddress address =
+ mPrivateAddressCoordinator.requestDownstreamAddress(
+ ipServer.interfaceType(),
+ scope,
+ useLastAddress,
+ ipServer.getIpv4PrefixRequest());
when(ipServer.getAddress()).thenReturn(address);
return address;
}
+ private void releaseDownstream(final IpServer ipServer) {
+ mPrivateAddressCoordinator.releaseDownstream(ipServer.getIpv4PrefixRequest());
+ }
+
private void updateUpstreamPrefix(UpstreamNetworkState ns) {
mPrivateAddressCoordinator.updateUpstreamPrefix(
ns.linkProperties, ns.networkCapabilities, ns.network);
@@ -145,8 +175,8 @@
assertNotEquals(usbPrefix, bluetoothPrefix);
assertNotEquals(usbPrefix, newHotspotPrefix);
- mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
+ releaseDownstream(mHotspotIpServer);
+ releaseDownstream(mUsbIpServer);
}
@Test
@@ -158,7 +188,7 @@
CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddress);
assertNotEquals(asIpPrefix(mBluetoothAddress), hotspotPrefix);
- mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
+ releaseDownstream(mHotspotIpServer);
// - Test previous enabled hotspot prefix(cached prefix) is reserved.
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(
@@ -168,7 +198,7 @@
final IpPrefix usbPrefix = asIpPrefix(usbAddress);
assertNotEquals(asIpPrefix(mBluetoothAddress), usbPrefix);
assertNotEquals(hotspotPrefix, usbPrefix);
- mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
+ releaseDownstream(mUsbIpServer);
// - Test wifi p2p prefix is reserved.
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(
@@ -179,7 +209,7 @@
assertNotEquals(asIpPrefix(mLegacyWifiP2pAddress), etherPrefix);
assertNotEquals(asIpPrefix(mBluetoothAddress), etherPrefix);
assertNotEquals(hotspotPrefix, etherPrefix);
- mPrivateAddressCoordinator.releaseDownstream(mEthernetIpServer);
+ releaseDownstream(mEthernetIpServer);
}
@Test
@@ -190,8 +220,8 @@
final LinkAddress usbAddress = requestDownstreamAddress(mUsbIpServer,
CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
- mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
+ releaseDownstream(mHotspotIpServer);
+ releaseDownstream(mUsbIpServer);
final LinkAddress newHotspotAddress = requestDownstreamAddress(mHotspotIpServer,
CONNECTIVITY_SCOPE_GLOBAL, true /* useLastAddress */);
@@ -254,10 +284,11 @@
}
private void verifyNotifyConflictAndRelease(final IpServer ipServer) throws Exception {
- verify(ipServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
- mPrivateAddressCoordinator.releaseDownstream(ipServer);
+ verify(ipServer).sendMessage(CMD_NOTIFY_PREFIX_CONFLICT);
+ releaseDownstream(ipServer);
+ final int interfaceType = ipServer.interfaceType();
reset(ipServer);
- setUpIpServers();
+ setUpIpServer(ipServer, interfaceType);
}
private int getSubAddress(final byte... ipv4Address) {
@@ -273,7 +304,7 @@
final IpPrefix hotspotPrefix = asIpPrefix(address);
final IpPrefix legacyWifiP2pPrefix = asIpPrefix(mLegacyWifiP2pAddress);
assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix);
- mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
+ releaseDownstream(mHotspotIpServer);
}
@Test
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 66fe957..d0c036f 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -71,7 +71,6 @@
import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_HIDL_1_0;
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_NONE;
-import static com.android.networkstack.tethering.PrivateAddressCoordinator.TETHER_FORCE_RANDOM_PREFIX_BASE_SELECTION;
import static com.android.networkstack.tethering.TestConnectivityManager.BROADCAST_FIRST;
import static com.android.networkstack.tethering.TestConnectivityManager.CALLBACKS_FIRST;
import static com.android.networkstack.tethering.Tethering.UserRestrictionActionListener;
@@ -97,6 +96,7 @@
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
@@ -192,7 +192,9 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.InterfaceParams;
+import com.android.net.module.util.PrivateAddressCoordinator;
import com.android.net.module.util.RoutingCoordinatorManager;
+import com.android.net.module.util.RoutingCoordinatorService;
import com.android.net.module.util.SharedLog;
import com.android.net.module.util.ip.IpNeighborMonitor;
import com.android.networkstack.apishim.common.BluetoothPanShim;
@@ -293,7 +295,6 @@
@Mock private BluetoothPanShim mBluetoothPanShim;
@Mock private TetheredInterfaceRequestShim mTetheredInterfaceRequestShim;
@Mock private TetheringMetrics mTetheringMetrics;
- @Mock private RoutingCoordinatorManager mRoutingCoordinatorManager;
@Mock private PrivateAddressCoordinator.Dependencies mPrivateAddressCoordinatorDependencies;
private final MockIpServerDependencies mIpServerDependencies =
@@ -318,12 +319,12 @@
private TetheringConfiguration mConfig;
private EntitlementManager mEntitleMgr;
private OffloadController mOffloadCtrl;
- private PrivateAddressCoordinator mPrivateAddressCoordinator;
private SoftApCallback mSoftApCallback;
private SoftApCallback mLocalOnlyHotspotCallback;
private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
private UpstreamNetworkMonitor.EventListener mEventListener;
private TetheredInterfaceCallbackShim mTetheredInterfaceCallbackShim;
+ private RoutingCoordinatorManager mRoutingCoordinatorManager;
private TestConnectivityManager mCm;
private boolean mForceEthernetServiceUnavailable = false;
@@ -489,8 +490,16 @@
}
@Override
- public RoutingCoordinatorManager getRoutingCoordinator(final Context context,
- SharedLog log) {
+ public RoutingCoordinatorManager getRoutingCoordinator(
+ final Context context, SharedLog log) {
+ ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
+ when(mPrivateAddressCoordinatorDependencies.isFeatureEnabled(anyString()))
+ .thenReturn(false);
+ RoutingCoordinatorService service = new RoutingCoordinatorService(
+ getINetd(context, log),
+ cm::getAllNetworks,
+ mPrivateAddressCoordinatorDependencies);
+ mRoutingCoordinatorManager = spy(new RoutingCoordinatorManager(context, service));
return mRoutingCoordinatorManager;
}
@@ -537,15 +546,6 @@
}
@Override
- public PrivateAddressCoordinator makePrivateAddressCoordinator(Context ctx) {
- ConnectivityManager cm = ctx.getSystemService(ConnectivityManager.class);
- mPrivateAddressCoordinator =
- new PrivateAddressCoordinator(
- cm::getAllNetworks, mPrivateAddressCoordinatorDependencies);
- return mPrivateAddressCoordinator;
- }
-
- @Override
public BluetoothPanShim makeBluetoothPanShim(BluetoothPan pan) {
try {
when(mBluetoothPanShim.requestTetheredInterface(
@@ -668,8 +668,6 @@
.thenReturn(true);
initOffloadConfiguration(OFFLOAD_HAL_VERSION_HIDL_1_0, 0 /* defaultDisabled */);
when(mOffloadHardwareInterface.getForwardedStats(any())).thenReturn(mForwardedStats);
- when(mPrivateAddressCoordinatorDependencies.isFeatureEnabled(anyString()))
- .thenReturn(false);
mServiceContext = new TestContext(mContext);
mServiceContext.setUseRegisteredHandlers(true);
@@ -687,6 +685,7 @@
new IntentFilter(ACTION_TETHER_STATE_CHANGED));
mCm = spy(new TestConnectivityManager(mServiceContext, mock(IConnectivityManager.class)));
+ when(mCm.getAllNetworks()).thenReturn(new Network[] {});
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(true);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true);
@@ -870,6 +869,9 @@
assertTrue(TestConnectivityManager.looksLikeDefaultRequest(reqCaptor.getValue()));
}
+ // Ignore calls to {@link ConnectivityManager#getallNetworks}.
+ verify(mCm, atLeast(0)).getAllNetworks();
+
// The default network request is only ever filed once.
verifyNoMoreInteractions(mCm);
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
index f540f10..c833422 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
@@ -35,7 +35,6 @@
import com.android.net.module.util.DnsUtils;
import com.android.net.module.util.HandlerUtils;
import com.android.net.module.util.SharedLog;
-import com.android.server.connectivity.mdns.util.MdnsUtils;
import java.io.IOException;
import java.io.PrintWriter;
@@ -211,7 +210,7 @@
void ensureRunningOnHandlerThread() {
synchronized (pendingTasks) {
- MdnsUtils.ensureRunningOnHandlerThread(handler);
+ HandlerUtils.ensureRunningOnHandlerThread(handler);
}
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
index c575d40..36fad31 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
@@ -16,7 +16,7 @@
package com.android.server.connectivity.mdns;
-import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
+import static com.android.net.module.util.HandlerUtils.ensureRunningOnHandlerThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java b/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java
index db3845a..a89b004 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsReplySender.java
@@ -16,9 +16,9 @@
package com.android.server.connectivity.mdns;
+import static com.android.net.module.util.HandlerUtils.ensureRunningOnHandlerThread;
import static com.android.server.connectivity.mdns.MdnsConstants.IPV4_SOCKET_ADDR;
import static com.android.server.connectivity.mdns.MdnsConstants.IPV6_SOCKET_ADDR;
-import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
import android.annotation.NonNull;
import android.annotation.RequiresApi;
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceCache.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceCache.java
index 22f7a03..4ae8701 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceCache.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceCache.java
@@ -18,8 +18,8 @@
import static com.android.net.module.util.DnsUtils.equalsIgnoreDnsCase;
import static com.android.net.module.util.DnsUtils.toDnsUpperCase;
+import static com.android.net.module.util.HandlerUtils.ensureRunningOnHandlerThread;
import static com.android.server.connectivity.mdns.MdnsResponse.EXPIRATION_NEVER;
-import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
import static java.lang.Math.min;
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
index a5dd536..4f01599 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -16,11 +16,12 @@
package com.android.server.connectivity.mdns;
+import static com.android.net.module.util.HandlerUtils.ensureRunningOnHandlerThread;
import static com.android.server.connectivity.mdns.MdnsSearchOptions.AGGRESSIVE_QUERY_MODE;
import static com.android.server.connectivity.mdns.MdnsServiceCache.ServiceExpiredCallback;
import static com.android.server.connectivity.mdns.MdnsServiceCache.findMatchedResponse;
import static com.android.server.connectivity.mdns.util.MdnsUtils.Clock;
-import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
+import static com.android.server.connectivity.mdns.util.MdnsUtils.buildMdnsServiceInfoFromResponse;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -41,10 +42,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.net.DatagramPacket;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
import java.net.InetSocketAddress;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -309,57 +307,6 @@
serviceCache.unregisterServiceExpiredCallback(cacheKey);
}
- private static MdnsServiceInfo buildMdnsServiceInfoFromResponse(@NonNull MdnsResponse response,
- @NonNull String[] serviceTypeLabels, long elapsedRealtimeMillis) {
- String[] hostName = null;
- int port = 0;
- if (response.hasServiceRecord()) {
- hostName = response.getServiceRecord().getServiceHost();
- port = response.getServiceRecord().getServicePort();
- }
-
- final List<String> ipv4Addresses = new ArrayList<>();
- final List<String> ipv6Addresses = new ArrayList<>();
- if (response.hasInet4AddressRecord()) {
- for (MdnsInetAddressRecord inetAddressRecord : response.getInet4AddressRecords()) {
- final Inet4Address inet4Address = inetAddressRecord.getInet4Address();
- ipv4Addresses.add((inet4Address == null) ? null : inet4Address.getHostAddress());
- }
- }
- if (response.hasInet6AddressRecord()) {
- for (MdnsInetAddressRecord inetAddressRecord : response.getInet6AddressRecords()) {
- final Inet6Address inet6Address = inetAddressRecord.getInet6Address();
- ipv6Addresses.add((inet6Address == null) ? null : inet6Address.getHostAddress());
- }
- }
- String serviceInstanceName = response.getServiceInstanceName();
- if (serviceInstanceName == null) {
- throw new IllegalStateException(
- "mDNS response must have non-null service instance name");
- }
- List<String> textStrings = null;
- List<MdnsServiceInfo.TextEntry> textEntries = null;
- if (response.hasTextRecord()) {
- textStrings = response.getTextRecord().getStrings();
- textEntries = response.getTextRecord().getEntries();
- }
- Instant now = Instant.now();
- // TODO: Throw an error message if response doesn't have Inet6 or Inet4 address.
- return new MdnsServiceInfo(
- serviceInstanceName,
- serviceTypeLabels,
- response.getSubtypes(),
- hostName,
- port,
- ipv4Addresses,
- ipv6Addresses,
- textStrings,
- textEntries,
- response.getInterfaceIndex(),
- response.getNetwork(),
- now.plusMillis(response.getMinRemainingTtl(elapsedRealtimeMillis)));
- }
-
private List<MdnsResponse> getExistingServices() {
return featureFlags.isQueryWithKnownAnswerEnabled()
? serviceCache.getCachedServices(cacheKey) : Collections.emptyList();
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
index 5c9ec09..b640c32 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
@@ -19,7 +19,8 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
+
+import static com.android.net.module.util.HandlerUtils.ensureRunningOnHandlerThread;
import static com.android.server.connectivity.mdns.util.MdnsUtils.isNetworkMatched;
import android.annotation.NonNull;
diff --git a/service-t/src/com/android/server/connectivity/mdns/MulticastPacketReader.java b/service-t/src/com/android/server/connectivity/mdns/MulticastPacketReader.java
index 70451f3..4d7e4bc 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MulticastPacketReader.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MulticastPacketReader.java
@@ -16,7 +16,7 @@
package com.android.server.connectivity.mdns;
-import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
+import static com.android.net.module.util.HandlerUtils.ensureRunningOnHandlerThread;
import android.annotation.NonNull;
import android.os.Handler;
diff --git a/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
index 8745941..41b15dd 100644
--- a/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
+++ b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
@@ -24,18 +24,22 @@
import android.annotation.Nullable;
import android.net.Network;
import android.os.Build;
-import android.os.Handler;
import android.os.SystemClock;
import android.util.ArraySet;
import android.util.Pair;
import com.android.server.connectivity.mdns.MdnsConstants;
+import com.android.server.connectivity.mdns.MdnsInetAddressRecord;
import com.android.server.connectivity.mdns.MdnsPacket;
import com.android.server.connectivity.mdns.MdnsPacketWriter;
import com.android.server.connectivity.mdns.MdnsRecord;
+import com.android.server.connectivity.mdns.MdnsResponse;
+import com.android.server.connectivity.mdns.MdnsServiceInfo;
import java.io.IOException;
import java.net.DatagramPacket;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
@@ -43,6 +47,7 @@
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -82,21 +87,6 @@
}
}
- /*** Ensure that current running thread is same as given handler thread */
- public static void ensureRunningOnHandlerThread(@NonNull Handler handler) {
- if (!isRunningOnHandlerThread(handler)) {
- throw new IllegalStateException(
- "Not running on Handler thread: " + Thread.currentThread().getName());
- }
- }
-
- /*** Check that current running thread is same as given handler thread */
- public static boolean isRunningOnHandlerThread(@NonNull Handler handler) {
- if (handler.getLooper().getThread() == Thread.currentThread()) {
- return true;
- }
- return false;
- }
/*** Check whether the target network matches the current network */
public static boolean isNetworkMatched(@Nullable Network targetNetwork,
@@ -318,4 +308,62 @@
}
return true;
}
+
+ /**
+ * Build MdnsServiceInfo object from given MdnsResponse, service type labels and current time.
+ *
+ * @param response target service response
+ * @param serviceTypeLabels service type labels
+ * @param elapsedRealtimeMillis current time.
+ */
+ public static MdnsServiceInfo buildMdnsServiceInfoFromResponse(@NonNull MdnsResponse response,
+ @NonNull String[] serviceTypeLabels, long elapsedRealtimeMillis) {
+ String[] hostName = null;
+ int port = 0;
+ if (response.hasServiceRecord()) {
+ hostName = response.getServiceRecord().getServiceHost();
+ port = response.getServiceRecord().getServicePort();
+ }
+
+ final List<String> ipv4Addresses = new ArrayList<>();
+ final List<String> ipv6Addresses = new ArrayList<>();
+ if (response.hasInet4AddressRecord()) {
+ for (MdnsInetAddressRecord inetAddressRecord : response.getInet4AddressRecords()) {
+ final Inet4Address inet4Address = inetAddressRecord.getInet4Address();
+ ipv4Addresses.add((inet4Address == null) ? null : inet4Address.getHostAddress());
+ }
+ }
+ if (response.hasInet6AddressRecord()) {
+ for (MdnsInetAddressRecord inetAddressRecord : response.getInet6AddressRecords()) {
+ final Inet6Address inet6Address = inetAddressRecord.getInet6Address();
+ ipv6Addresses.add((inet6Address == null) ? null : inet6Address.getHostAddress());
+ }
+ }
+ String serviceInstanceName = response.getServiceInstanceName();
+ if (serviceInstanceName == null) {
+ throw new IllegalStateException(
+ "mDNS response must have non-null service instance name");
+ }
+ List<String> textStrings = null;
+ List<MdnsServiceInfo.TextEntry> textEntries = null;
+ if (response.hasTextRecord()) {
+ textStrings = response.getTextRecord().getStrings();
+ textEntries = response.getTextRecord().getEntries();
+ }
+ Instant now = Instant.now();
+ // TODO: Throw an error message if response doesn't have Inet6 or Inet4 address.
+ return new MdnsServiceInfo(
+ serviceInstanceName,
+ serviceTypeLabels,
+ response.getSubtypes(),
+ hostName,
+ port,
+ ipv4Addresses,
+ ipv6Addresses,
+ textStrings,
+ textEntries,
+ response.getInterfaceIndex(),
+ response.getNetwork(),
+ now.plusMillis(response.getMinRemainingTtl(elapsedRealtimeMillis)));
+ }
}
\ No newline at end of file
diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
index cadc04d..1ac99e4 100644
--- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
+++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
@@ -202,20 +202,6 @@
return;
}
- private static NetworkCapabilities mixInCapabilities(NetworkCapabilities nc,
- NetworkCapabilities addedNc) {
- final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(nc);
- for (int transport : addedNc.getTransportTypes()) builder.addTransportType(transport);
- for (int capability : addedNc.getCapabilities()) builder.addCapability(capability);
- return builder.build();
- }
-
- private static NetworkCapabilities createDefaultNetworkCapabilities() {
- return NetworkCapabilities.Builder
- .withoutDefaultCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET).build();
- }
-
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
protected boolean removeInterface(String interfaceName) {
NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName);
@@ -556,14 +542,6 @@
maybeRestart();
}
- private void ensureRunningOnEthernetHandlerThread() {
- if (mHandler.getLooper().getThread() != Thread.currentThread()) {
- throw new IllegalStateException(
- "Not running on the Ethernet thread: "
- + Thread.currentThread().getName());
- }
- }
-
private void handleOnLinkPropertiesChange(LinkProperties linkProperties) {
mLinkProperties = linkProperties;
if (mNetworkAgent != null) {
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index cb62ae1..a04ebdd 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -2028,7 +2028,8 @@
mCdmps = null;
}
- mRoutingCoordinatorService = new RoutingCoordinatorService(netd);
+ mRoutingCoordinatorService =
+ new RoutingCoordinatorService(netd, this::getAllNetworks, mContext);
mMulticastRoutingCoordinatorService =
mDeps.makeMulticastRoutingCoordinatorService(mHandler);
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index 9d27608..66e1dad 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -650,6 +650,7 @@
name: "net-utils-all-srcs",
srcs: [
"device/**/*.java",
+ ":framework-connectivity-shared-srcs",
":net-utils-framework-common-srcs",
],
visibility: ["//visibility:private"],
diff --git a/staticlibs/device/com/android/net/module/util/HandlerUtils.java b/staticlibs/device/com/android/net/module/util/HandlerUtils.java
index c620368..991df8f 100644
--- a/staticlibs/device/com/android/net/module/util/HandlerUtils.java
+++ b/staticlibs/device/com/android/net/module/util/HandlerUtils.java
@@ -102,4 +102,37 @@
if (e != null) throw e;
return true;
}
+
+ /**
+ * Ensures that the current running thread is the same as the thread associated with the given
+ * handler.
+ *
+ * @param handler The handler whose thread to compare.
+ * @throws IllegalStateException if the thread associated with the given handler is not the same
+ * as the current running thread.
+ * @hide
+ */
+ public static void ensureRunningOnHandlerThread(@NonNull Handler handler) {
+ if (!isRunningOnHandlerThread(handler)) {
+ throw new IllegalStateException(
+ "Not running on Handler thread: " + Thread.currentThread().getName());
+ }
+ }
+
+ /**
+ * Checks if the current running thread is the same as the thread associated with the given
+ * handler.
+ *
+ * @param handler The handler whose thread to compare.
+ * @return {@code true} if the thread associated with the given handler is the same as the
+ * current running thread, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public static boolean isRunningOnHandlerThread(@NonNull Handler handler) {
+ if (handler.getLooper().getThread() == Thread.currentThread()) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/staticlibs/device/com/android/net/module/util/IIpv4PrefixRequest.aidl b/staticlibs/device/com/android/net/module/util/IIpv4PrefixRequest.aidl
new file mode 100644
index 0000000..cc1c19c
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/IIpv4PrefixRequest.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.net.module.util;
+
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+
+/** @hide */
+// TODO: b/350630377 - This @Descriptor annotation workaround is to prevent the class from being
+// jarjared which changes the DESCRIPTOR and casues "java.lang.SecurityException: Binder invocation
+// to an incorrect interface" when calling the IPC.
+@Descriptor("value=no.jarjar.com.android.net.module.util.IIpv4PrefixRequest")
+interface IIpv4PrefixRequest {
+ void onIpv4PrefixConflict(in IpPrefix ipPrefix);
+}
diff --git a/staticlibs/device/com/android/net/module/util/IRoutingCoordinator.aidl b/staticlibs/device/com/android/net/module/util/IRoutingCoordinator.aidl
index 72a4a94..097824f 100644
--- a/staticlibs/device/com/android/net/module/util/IRoutingCoordinator.aidl
+++ b/staticlibs/device/com/android/net/module/util/IRoutingCoordinator.aidl
@@ -16,8 +16,14 @@
package com.android.net.module.util;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.RouteInfo;
+import com.android.net.module.util.IIpv4PrefixRequest;
+
/** @hide */
// TODO: b/350630377 - This @Descriptor annotation workaround is to prevent the DESCRIPTOR from
// being jarjared which changes the DESCRIPTOR and casues "java.lang.SecurityException: Binder
@@ -96,4 +102,34 @@
* cause of the failure.
*/
void removeInterfaceForward(in String fromIface, in String toIface);
+
+ /** Update the prefix of an upstream. */
+ void updateUpstreamPrefix(in @nullable LinkProperties lp,
+ in @nullable NetworkCapabilities nc,
+ in Network network);
+
+ /** Remove the upstream prefix of the given {@link Network}. */
+ void removeUpstreamPrefix(in Network network);
+
+ /** Remove the deprecated upstream networks if any. */
+ void maybeRemoveDeprecatedUpstreams();
+
+ /**
+ * Request an IPv4 address for the downstream.
+ *
+ * @param interfaceType the Tethering type (see TetheringManager#TETHERING_*).
+ * @param scope CONNECTIVITY_SCOPE_GLOBAL or CONNECTIVITY_SCOPE_LOCAL
+ * @param useLastAddress whether to use the last address
+ * @param request a {@link IIpv4PrefixRequest} to report conflicts
+ * @return an IPv4 address allocated for the downstream, could be null
+ */
+ @nullable
+ LinkAddress requestDownstreamAddress(
+ in int interfaceType,
+ in int scope,
+ in boolean useLastAddress,
+ in IIpv4PrefixRequest request);
+
+ /** Release the IPv4 address allocated for the downstream. */
+ void releaseDownstream(in IIpv4PrefixRequest request);
}
diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/staticlibs/device/com/android/net/module/util/PrivateAddressCoordinator.java
similarity index 82%
rename from Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
rename to staticlibs/device/com/android/net/module/util/PrivateAddressCoordinator.java
index 50f82cf..990358d 100644
--- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/staticlibs/device/com/android/net/module/util/PrivateAddressCoordinator.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.networkstack.tethering;
+package com.android.net.module.util;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
@@ -24,7 +24,6 @@
import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
-import static com.android.networkstack.tethering.util.PrefixUtils.asIpPrefix;
import static java.util.Arrays.asList;
@@ -34,16 +33,13 @@
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.ip.IpServer;
+import android.os.RemoteException;
import android.util.ArrayMap;
-import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.net.module.util.DeviceConfigUtils;
import java.net.Inet4Address;
import java.net.InetAddress;
@@ -51,6 +47,8 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.function.Supplier;
@@ -62,7 +60,7 @@
* coordinator is responsible for recording all of network assigned addresses and dispatched
* free address to downstream interfaces.
*
- * This class is not thread-safe and should be accessed on the same tethering internal thread.
+ * This class is not thread-safe.
* @hide
*/
public class PrivateAddressCoordinator {
@@ -78,7 +76,9 @@
// when tethering is down. Instead tethering would remove all deprecated upstreams from
// mUpstreamPrefixMap when tethering is starting. See #maybeRemoveDeprecatedUpstreams().
private final ArrayMap<Network, List<IpPrefix>> mUpstreamPrefixMap;
- private final ArraySet<IpServer> mDownstreams;
+ // The downstreams are indexed by Ipv4PrefixRequest, which is a wrapper of the Binder object of
+ // IIpv4PrefixRequest.
+ private final ArrayMap<Ipv4PrefixRequest, Downstream> mDownstreams;
private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24";
private static final String LEGACY_BLUETOOTH_IFACE_ADDRESS = "192.168.44.1/24";
private final List<IpPrefix> mTetheringPrefixes;
@@ -116,7 +116,7 @@
@VisibleForTesting
public PrivateAddressCoordinator(Supplier<Network[]> getAllNetworksSupplier,
Dependencies deps) {
- mDownstreams = new ArraySet<>();
+ mDownstreams = new ArrayMap<>();
mUpstreamPrefixMap = new ArrayMap<>();
mGetAllNetworksSupplier = getAllNetworksSupplier;
mDeps = deps;
@@ -168,12 +168,18 @@
}
private void handleMaybePrefixConflict(final List<IpPrefix> prefixes) {
- for (IpServer downstream : mDownstreams) {
- final IpPrefix target = getDownstreamPrefix(downstream);
+ for (Map.Entry<Ipv4PrefixRequest, Downstream> entry : mDownstreams.entrySet()) {
+ final Ipv4PrefixRequest request = entry.getKey();
+ final Downstream downstream = entry.getValue();
+ final IpPrefix target = asIpPrefix(downstream.getAddress());
for (IpPrefix source : prefixes) {
if (isConflictPrefix(source, target)) {
- downstream.sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+ try {
+ request.getRequest().onIpv4PrefixConflict(target);
+ } catch (RemoteException ignored) {
+ // ignore
+ }
break;
}
}
@@ -199,21 +205,26 @@
mUpstreamPrefixMap.removeAll(toBeRemoved);
}
+ // TODO: There needs to be a reserveDownstreamAddress() method for the cases where
+ // TetheringRequest has been set a static IPv4 address.
+
/**
* Pick a random available address and mark its prefix as in use for the provided IpServer,
* returns null if there is no available address.
*/
@Nullable
- public LinkAddress requestDownstreamAddress(final IpServer ipServer, final int scope,
- boolean useLastAddress) {
- final AddressKey addrKey = new AddressKey(ipServer.interfaceType(), scope);
+ public LinkAddress requestDownstreamAddress(int interfaceType, final int scope,
+ boolean useLastAddress,
+ IIpv4PrefixRequest request) {
+ final Ipv4PrefixRequest wrappedRequest = new Ipv4PrefixRequest(request);
+ final AddressKey addrKey = new AddressKey(interfaceType, scope);
// This ensures that tethering isn't started on 2 different interfaces with the same type.
// Once tethering could support multiple interface with the same type,
// TetheringSoftApCallback would need to handle it among others.
final LinkAddress cachedAddress = mCachedAddresses.get(addrKey);
if (useLastAddress && cachedAddress != null
&& !isConflictWithUpstream(asIpPrefix(cachedAddress))) {
- mDownstreams.add(ipServer);
+ mDownstreams.put(wrappedRequest, new Downstream(interfaceType, cachedAddress));
return cachedAddress;
}
@@ -223,7 +234,7 @@
(prefixIndex + i) % mTetheringPrefixes.size());
final LinkAddress newAddress = chooseDownstreamAddress(prefixRange);
if (newAddress != null) {
- mDownstreams.add(ipServer);
+ mDownstreams.put(wrappedRequest, new Downstream(interfaceType, newAddress));
mCachedAddresses.put(addrKey, newAddress);
return newAddress;
}
@@ -327,8 +338,8 @@
}
/** Release downstream record for IpServer. */
- public void releaseDownstream(final IpServer ipServer) {
- mDownstreams.remove(ipServer);
+ public void releaseDownstream(IIpv4PrefixRequest request) {
+ mDownstreams.remove(new Ipv4PrefixRequest(request));
}
/** Clear current upstream prefixes records. */
@@ -368,8 +379,8 @@
// IpServer may use manually-defined address (mStaticIpv4ServerAddr) which does not include
// in mCachedAddresses.
- for (IpServer downstream : mDownstreams) {
- final IpPrefix target = getDownstreamPrefix(downstream);
+ for (Downstream downstream : mDownstreams.values()) {
+ final IpPrefix target = asIpPrefix(downstream.getAddress());
if (isConflictPrefix(prefix, target)) return target;
}
@@ -377,11 +388,51 @@
return null;
}
- @NonNull
- private IpPrefix getDownstreamPrefix(final IpServer downstream) {
- final LinkAddress address = downstream.getAddress();
+ private static IpPrefix asIpPrefix(LinkAddress addr) {
+ return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
+ }
- return asIpPrefix(address);
+ private static final class Ipv4PrefixRequest {
+ private final IIpv4PrefixRequest mRequest;
+
+ Ipv4PrefixRequest(IIpv4PrefixRequest request) {
+ mRequest = request;
+ }
+
+ public IIpv4PrefixRequest getRequest() {
+ return mRequest;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!(obj instanceof Ipv4PrefixRequest)) return false;
+ return Objects.equals(
+ mRequest.asBinder(), ((Ipv4PrefixRequest) obj).mRequest.asBinder());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(mRequest.asBinder());
+ }
+ }
+
+ private static final class Downstream {
+ private final int mInterfaceType;
+ private final LinkAddress mAddress;
+
+ private Downstream(int interfaceType, LinkAddress address) {
+ mInterfaceType = interfaceType;
+ mAddress = address;
+ }
+
+ public int getInterfaceType() {
+ return mInterfaceType;
+ }
+
+ public LinkAddress getAddress() {
+ return mAddress;
+ }
}
private static class AddressKey {
@@ -412,6 +463,7 @@
}
}
+ // TODO: dump PrivateAddressCoordinator when dumping RoutingCoordinatorService.
void dump(final IndentingPrintWriter pw) {
pw.println("mTetheringPrefixes:");
pw.increaseIndent();
@@ -429,8 +481,8 @@
pw.println("mDownstreams:");
pw.increaseIndent();
- for (IpServer ipServer : mDownstreams) {
- pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress());
+ for (Downstream downstream : mDownstreams.values()) {
+ pw.println(downstream.getInterfaceType() + " - " + downstream.getAddress());
}
pw.decreaseIndent();
diff --git a/staticlibs/device/com/android/net/module/util/RoutingCoordinatorManager.java b/staticlibs/device/com/android/net/module/util/RoutingCoordinatorManager.java
index 02e3643..9ea0947 100644
--- a/staticlibs/device/com/android/net/module/util/RoutingCoordinatorManager.java
+++ b/staticlibs/device/com/android/net/module/util/RoutingCoordinatorManager.java
@@ -17,17 +17,27 @@
package com.android.net.module.util;
import android.content.Context;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.RouteInfo;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
/**
* A manager class for talking to the routing coordinator service.
*
* This class should only be used by the connectivity and tethering module. This is enforced
* by the build rules. Do not change build rules to gain access to this class from elsewhere.
+ *
+ * This class has following functionalities:
+ * - Manage routes and forwarding for networks.
+ * - Manage IPv4 prefix allocation for network interfaces.
+ *
* @hide
*/
public class RoutingCoordinatorManager {
@@ -154,4 +164,65 @@
throw e.rethrowFromSystemServer();
}
}
+
+ // PrivateAddressCoordinator methods:
+
+ /** Update the prefix of an upstream. */
+ public void updateUpstreamPrefix(LinkProperties lp, NetworkCapabilities nc, Network network) {
+ try {
+ mService.updateUpstreamPrefix(lp, nc, network);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** Remove the upstream prefix of the given {@link Network}. */
+ public void removeUpstreamPrefix(Network network) {
+ try {
+ mService.removeUpstreamPrefix(network);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** Remove the deprecated upstream networks if any. */
+ public void maybeRemoveDeprecatedUpstreams() {
+ try {
+ mService.maybeRemoveDeprecatedUpstreams();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Request an IPv4 address for the downstream.
+ *
+ * @param interfaceType the Tethering type (see TetheringManager#TETHERING_*).
+ * @param scope CONNECTIVITY_SCOPE_GLOBAL or CONNECTIVITY_SCOPE_LOCAL
+ * @param useLastAddress whether to use the last address
+ * @param request a {@link IIpv4PrefixRequest} to report conflicts
+ * @return an IPv4 address allocated for the downstream, could be null
+ */
+ @Nullable
+ public LinkAddress requestDownstreamAddress(
+ int interfaceType,
+ int scope,
+ boolean useLastAddress,
+ IIpv4PrefixRequest request) {
+ try {
+ return mService.requestDownstreamAddress(
+ interfaceType, scope, useLastAddress, request);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** Release the IPv4 address allocated for the downstream. */
+ public void releaseDownstream(IIpv4PrefixRequest request) {
+ try {
+ mService.releaseDownstream(request);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/staticlibs/device/com/android/net/module/util/RoutingCoordinatorService.java b/staticlibs/device/com/android/net/module/util/RoutingCoordinatorService.java
index c75b860..d16c234 100644
--- a/staticlibs/device/com/android/net/module/util/RoutingCoordinatorService.java
+++ b/staticlibs/device/com/android/net/module/util/RoutingCoordinatorService.java
@@ -19,8 +19,13 @@
import static com.android.net.module.util.NetdUtils.toRouteInfoParcel;
import android.annotation.NonNull;
+import android.content.Context;
import android.net.INetd;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.RouteInfo;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -28,8 +33,10 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.Objects;
+import java.util.function.Supplier;
/**
* Class to coordinate routing across multiple clients.
@@ -45,8 +52,22 @@
private static final String TAG = RoutingCoordinatorService.class.getSimpleName();
private final INetd mNetd;
- public RoutingCoordinatorService(@NonNull INetd netd) {
+ private final Object mPrivateAddressCoordinatorLock = new Object();
+ @GuardedBy("mPrivateAddressCoordinatorLock")
+ private final PrivateAddressCoordinator mPrivateAddressCoordinator;
+
+ public RoutingCoordinatorService(@NonNull INetd netd,
+ @NonNull Supplier<Network[]> getAllNetworksSupplier,
+ @NonNull Context context) {
+ this(netd, getAllNetworksSupplier, new PrivateAddressCoordinator.Dependencies(context));
+ }
+
+ @VisibleForTesting
+ public RoutingCoordinatorService(@NonNull INetd netd,
+ @NonNull Supplier<Network[]> getAllNetworksSupplier,
+ @NonNull PrivateAddressCoordinator.Dependencies pacDeps) {
mNetd = netd;
+ mPrivateAddressCoordinator = new PrivateAddressCoordinator(getAllNetworksSupplier, pacDeps);
}
/**
@@ -225,4 +246,74 @@
}
}
}
+
+ // PrivateAddressCoordinator methods:
+
+ /** Update the prefix of an upstream. */
+ @Override
+ public void updateUpstreamPrefix(LinkProperties lp, NetworkCapabilities nc, Network network) {
+ BinderUtils.withCleanCallingIdentity(
+ () -> {
+ synchronized (mPrivateAddressCoordinatorLock) {
+ mPrivateAddressCoordinator.updateUpstreamPrefix(lp, nc, network);
+ }
+ });
+ }
+
+ /** Remove the upstream prefix of the given {@link Network}. */
+ @Override
+ public void removeUpstreamPrefix(Network network) {
+ Objects.requireNonNull(network);
+ BinderUtils.withCleanCallingIdentity(
+ () -> {
+ synchronized (mPrivateAddressCoordinatorLock) {
+ mPrivateAddressCoordinator.removeUpstreamPrefix(network);
+ }
+ });
+ }
+
+ /** Remove the deprecated upstream networks if any. */
+ @Override
+ public void maybeRemoveDeprecatedUpstreams() {
+ BinderUtils.withCleanCallingIdentity(
+ () -> {
+ synchronized (mPrivateAddressCoordinatorLock) {
+ mPrivateAddressCoordinator.maybeRemoveDeprecatedUpstreams();
+ }
+ });
+ }
+
+ /**
+ * Request an IPv4 address for the downstream.
+ *
+ * @param interfaceType the Tethering type (see TetheringManager#TETHERING_*).
+ * @param scope CONNECTIVITY_SCOPE_GLOBAL or CONNECTIVITY_SCOPE_LOCAL
+ * @param useLastAddress whether to use the last address
+ * @param request a {@link IIpv4PrefixRequest} to report conflicts
+ * @return an IPv4 address allocated for the downstream, could be null
+ */
+ @Override
+ public LinkAddress requestDownstreamAddress(int interfaceType, int scope,
+ boolean useLastAddress, IIpv4PrefixRequest request) {
+ Objects.requireNonNull(request);
+ return BinderUtils.withCleanCallingIdentity(
+ () -> {
+ synchronized (mPrivateAddressCoordinatorLock) {
+ return mPrivateAddressCoordinator.requestDownstreamAddress(
+ interfaceType, scope, useLastAddress, request);
+ }
+ });
+ }
+
+ /** Release the IPv4 address allocated for the downstream. */
+ @Override
+ public void releaseDownstream(IIpv4PrefixRequest request) {
+ Objects.requireNonNull(request);
+ BinderUtils.withCleanCallingIdentity(
+ () -> {
+ synchronized (mPrivateAddressCoordinatorLock) {
+ mPrivateAddressCoordinator.releaseDownstream(request);
+ }
+ });
+ }
}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
index f34159e..541a375 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
@@ -30,7 +30,6 @@
import static android.system.OsConstants.SO_RCVTIMEO;
import static android.system.OsConstants.SO_SNDTIMEO;
-import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWLINK;
import static com.android.net.module.util.netlink.NetlinkConstants.hexify;
import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE;
import static com.android.net.module.util.netlink.NetlinkConstants.RTNL_FAMILY_IP6MR;
@@ -58,7 +57,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
/**
@@ -227,96 +225,6 @@
}
/**
- * Sends an RTM_NEWLINK message to kernel to set a network interface up or down.
- *
- * @param ifName The name of the network interface to modify.
- * @param isUp {@code true} to set the interface up, {@code false} to set it down.
- * @return {@code true} if the request was successfully sent, {@code false} otherwise.
- */
- public static boolean sendRtmSetLinkStateRequest(@NonNull String ifName, boolean isUp) {
- final RtNetlinkLinkMessage msg = RtNetlinkLinkMessage.createSetLinkStateMessage(
- ifName, 1 /*sequenceNumber*/, isUp);
- if (msg == null) {
- return false;
- }
-
- final byte[] bytes = msg.pack(ByteOrder.nativeOrder());
- try {
- NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, bytes);
- return true;
- } catch (ErrnoException e) {
- Log.e(TAG, "Fail to set the interface " + ifName + " " + (isUp ? "up" : "down"), e);
- return false;
- }
- }
-
- /**
- * Sends an RTM_NEWLINK message to kernel to rename a network interface.
- *
- * @param ifName The current name of the network interface.
- * @param newIfName The new name to assign to the interface.
- * @return {@code true} if the request was successfully sent, {@code false} otherwise.
- */
- public static boolean sendRtmSetLinkNameRequest(
- @NonNull String ifName, @NonNull String newIfName) {
- final RtNetlinkLinkMessage msg = RtNetlinkLinkMessage.createSetLinkNameMessage(
- ifName, 1 /*sequenceNumber*/, newIfName);
- if (msg == null) {
- return false;
- }
-
- final byte[] bytes = msg.pack(ByteOrder.nativeOrder());
- try {
- NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, bytes);
- return true;
- } catch (ErrnoException e) {
- Log.e(TAG, "Fail to rename the interface from " + ifName + " to " + newIfName, e);
- return false;
- }
- }
-
- /**
- * Gets the information of a network interface using a Netlink message.
- * <p>
- * This method sends a Netlink message to the kernel to request information about the specified
- * network interface and returns a {@link RtNetlinkLinkMessage} containing the interface status.
- *
- * @param ifName The name of the network interface to query.
- * @return An {@link RtNetlinkLinkMessage} containing the interface status, or {@code null} if
- * the interface does not exist or an error occurred during the query.
- */
- @Nullable
- public static RtNetlinkLinkMessage getLinkRequest(@NonNull String ifName) {
- final int ifIndex = new OsAccess().if_nametoindex(ifName);
- if (ifIndex == OsAccess.INVALID_INTERFACE_INDEX) {
- return null;
- }
-
- final AtomicReference<RtNetlinkLinkMessage> recvMsg = new AtomicReference<>();
- final Consumer<RtNetlinkLinkMessage> handleNlMsg = (msg) -> {
- if (msg.getHeader().nlmsg_type == RTM_NEWLINK
- && msg.getIfinfoHeader().index == ifIndex) {
- recvMsg.set(msg);
- }
- };
-
- final RtNetlinkLinkMessage msg = RtNetlinkLinkMessage.createGetLinkMessage(
- ifName, 1 /*sequenceNumber*/);
- if (msg == null) {
- return null;
- }
-
- final byte[] bytes = msg.pack(ByteOrder.nativeOrder());
- try {
- NetlinkUtils.getAndProcessNetlinkDumpMessages(
- bytes, NETLINK_ROUTE, RtNetlinkLinkMessage.class, handleNlMsg);
- } catch (SocketException | InterruptedIOException | ErrnoException e) {
- // Nothing we can do here.
- }
- return recvMsg.get();
- }
-
- /**
* Create netlink socket with the given netlink protocol type and buffersize.
*
* @param nlProto the netlink protocol
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/HandlerUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/HandlerUtilsTest.kt
index f2c902f..845a2c3 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/HandlerUtilsTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/HandlerUtilsTest.kt
@@ -19,11 +19,14 @@
import android.os.HandlerThread
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.DevSdkIgnoreRunner.MonitorThreadLeak
+import com.android.testutils.waitForIdle
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import org.junit.After
import org.junit.Test
import org.junit.runner.RunWith
+import kotlin.test.assertFailsWith
+import kotlin.test.assertFalse
const val THREAD_BLOCK_TIMEOUT_MS = 1000L
const val TEST_REPEAT_COUNT = 100
@@ -52,6 +55,24 @@
}
}
+ @Test
+ fun testIsRunningOnHandlerThread() {
+ assertFalse(HandlerUtils.isRunningOnHandlerThread(handler))
+ handler.post{
+ assertTrue(HandlerUtils.isRunningOnHandlerThread(handler))
+ }
+ handler.waitForIdle(THREAD_BLOCK_TIMEOUT_MS)
+ }
+
+ @Test
+ fun testEnsureRunningOnHandlerThread() {
+ assertFailsWith<IllegalStateException>{ HandlerUtils.ensureRunningOnHandlerThread(handler) }
+ handler.post{
+ HandlerUtils.ensureRunningOnHandlerThread(handler)
+ }
+ handler.waitForIdle(THREAD_BLOCK_TIMEOUT_MS)
+ }
+
@After
fun tearDown() {
handlerThread.quitSafely()
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/RoutingCoordinatorServiceTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/RoutingCoordinatorServiceTest.kt
index b04561c..035ce0f 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/RoutingCoordinatorServiceTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/RoutingCoordinatorServiceTest.kt
@@ -16,7 +16,9 @@
package com.android.net.module.util
+import android.content.Context
import android.net.INetd
+import android.net.Network
import android.os.Build
import android.util.Log
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
@@ -34,7 +36,9 @@
@IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
class RoutingCoordinatorServiceTest {
val mNetd = mock(INetd::class.java)
- val mService = RoutingCoordinatorService(mNetd)
+ val mGetAllNetworksSupplier = { emptyArray<Network>() }
+ val mContext = mock(Context::class.java)
+ val mService = RoutingCoordinatorService(mNetd, mGetAllNetworksSupplier, mContext)
@Test
fun testInterfaceForward() {
diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp
index 8c71a91..13e1dc0 100644
--- a/staticlibs/testutils/Android.bp
+++ b/staticlibs/testutils/Android.bp
@@ -33,6 +33,7 @@
],
static_libs: [
"androidx.test.ext.junit",
+ "collector-device-lib",
"kotlin-reflect",
"libnanohttpd",
"net-tests-utils-host-device-common",
diff --git a/staticlibs/testutils/devicetests/NSResponder.kt b/staticlibs/testutils/devicetests/NSResponder.kt
index f7619cd..f094407 100644
--- a/staticlibs/testutils/devicetests/NSResponder.kt
+++ b/staticlibs/testutils/devicetests/NSResponder.kt
@@ -35,12 +35,12 @@
private const val NS_TYPE = 135.toShort()
/**
- * A class that can be used to reply to Neighbor Solicitation packets on a [TapPacketReader].
+ * A class that can be used to reply to Neighbor Solicitation packets on a [PollPacketReader].
*/
class NSResponder(
- reader: TapPacketReader,
- table: Map<Inet6Address, MacAddress>,
- name: String = NSResponder::class.java.simpleName
+ reader: PollPacketReader,
+ table: Map<Inet6Address, MacAddress>,
+ name: String = NSResponder::class.java.simpleName
) : PacketResponder(reader, Icmpv6Filter(), name) {
companion object {
private val TAG = NSResponder::class.simpleName
@@ -49,7 +49,7 @@
// Copy the map if not already immutable (toMap) to make sure it is not modified
private val table = table.toMap()
- override fun replyToPacket(packet: ByteArray, reader: TapPacketReader) {
+ override fun replyToPacket(packet: ByteArray, reader: PollPacketReader) {
if (packet.size < IPV6_HEADER_LENGTH) {
return
}
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt b/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt
index cf0490c..f4c8657 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/ArpResponder.kt
@@ -30,17 +30,17 @@
private val ARP_REPLY_IPV4 = byteArrayOf(0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02)
/**
- * A class that can be used to reply to ARP packets on a [TapPacketReader].
+ * A class that can be used to reply to ARP packets on a [PollPacketReader].
*/
class ArpResponder(
- reader: TapPacketReader,
- table: Map<Inet4Address, MacAddress>,
- name: String = ArpResponder::class.java.simpleName
+ reader: PollPacketReader,
+ table: Map<Inet4Address, MacAddress>,
+ name: String = ArpResponder::class.java.simpleName
) : PacketResponder(reader, ArpRequestFilter(), name) {
// Copy the map if not already immutable (toMap) to make sure it is not modified
private val table = table.toMap()
- override fun replyToPacket(packet: ByteArray, reader: TapPacketReader) {
+ override fun replyToPacket(packet: ByteArray, reader: PollPacketReader) {
val targetIp = InetAddress.getByAddress(
packet.copyFromIndexWithLength(ARP_TARGET_IPADDR_OFFSET, 4))
as Inet4Address
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt
new file mode 100644
index 0000000..f5a5b4d
--- /dev/null
+++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2024 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.testutils
+
+import android.device.collectors.BaseMetricListener
+import android.device.collectors.DataRecord
+import android.os.Build
+import android.os.ParcelFileDescriptor
+import android.util.Log
+import androidx.test.platform.app.InstrumentationRegistry
+import java.io.ByteArrayOutputStream
+import java.io.File
+import java.io.PrintWriter
+import java.time.ZonedDateTime
+import kotlin.test.assertNull
+import org.junit.AssumptionViolatedException
+import org.junit.runner.Description
+import org.junit.runner.notification.Failure
+
+/**
+ * A diagnostics collector that outputs diagnostics files as test artifacts.
+ *
+ * <p>Collects diagnostics automatically by default on non-local builds. Can be enabled/disabled
+ * manually with:
+ * ```
+ * atest MyModule -- \
+ * --module-arg MyModule:instrumentation-arg:connectivity-diagnostics-on-failure:=false
+ * ```
+ */
+class ConnectivityDiagnosticsCollector : BaseMetricListener() {
+ companion object {
+ private const val ARG_RUN_ON_FAILURE = "connectivity-diagnostics-on-failure"
+ private const val COLLECTOR_DIR = "run_listeners/connectivity_diagnostics"
+ private const val FILENAME_SUFFIX = "_conndiag.txt"
+ private const val MAX_DUMPS = 20
+
+ private val TAG = ConnectivityDiagnosticsCollector::class.simpleName
+ var instance: ConnectivityDiagnosticsCollector? = null
+ }
+
+ private val buffer = ByteArrayOutputStream()
+ private val collectorDir: File by lazy {
+ createAndEmptyDirectory(COLLECTOR_DIR)
+ }
+ private val outputFiles = mutableSetOf<String>()
+
+ override fun onSetUp() {
+ assertNull(instance, "ConnectivityDiagnosticsCollectors were set up multiple times")
+ instance = this
+ TryTestConfig.setDiagnosticsCollector { throwable ->
+ if (runOnFailure(throwable)) {
+ collectTestFailureDiagnostics(throwable)
+ }
+ }
+ }
+
+ override fun onCleanUp() {
+ instance = null
+ }
+
+ override fun onTestFail(testData: DataRecord, description: Description, failure: Failure) {
+ // TODO: find a way to disable this behavior only on local runs, to avoid slowing them down
+ // when iterating on failing tests.
+ if (!runOnFailure(failure.exception)) return
+ if (outputFiles.size >= MAX_DUMPS) return
+ Log.i(TAG, "Collecting diagnostics for test failure. Disable by running tests with: " +
+ "atest MyModule -- " +
+ "--module-arg MyModule:instrumentation-arg:$ARG_RUN_ON_FAILURE:=false")
+ collectTestFailureDiagnostics(failure.exception)
+
+ val baseFilename = "${description.className}#${description.methodName}_failure"
+ flushBufferToFileMetric(testData, baseFilename)
+ }
+
+ override fun onTestEnd(testData: DataRecord, description: Description) {
+ // Tests may call methods like collectDumpsysConnectivity to collect diagnostics at any time
+ // during the run, for example to observe state at various points to investigate a flake
+ // and compare passing/failing cases.
+ // Flush the contents of the buffer to a file when the test ends, even when successful.
+ if (buffer.size() == 0) return
+ if (outputFiles.size >= MAX_DUMPS) return
+
+ // Flush any data that the test added to the buffer for dumping
+ val baseFilename = "${description.className}#${description.methodName}_testdump"
+ flushBufferToFileMetric(testData, baseFilename)
+ }
+
+ private fun runOnFailure(exception: Throwable): Boolean {
+ // Assumption failures (assumeTrue/assumeFalse) are not actual failures
+ if (exception is AssumptionViolatedException) return false
+
+ // Do not run on local builds (which have ro.build.version.incremental set to eng.username)
+ // to avoid slowing down local runs.
+ val enabledByDefault = !Build.VERSION.INCREMENTAL.startsWith("eng.")
+ return argsBundle.getString(ARG_RUN_ON_FAILURE)?.toBooleanStrictOrNull() ?: enabledByDefault
+ }
+
+ private fun flushBufferToFileMetric(testData: DataRecord, baseFilename: String) {
+ var filename = baseFilename
+ // In case a method was run multiple times (typically retries), append a number
+ var i = 2
+ while (outputFiles.contains(filename)) {
+ filename = baseFilename + "_$i"
+ i++
+ }
+ val outFile = File(collectorDir, filename + FILENAME_SUFFIX)
+ outputFiles.add(filename)
+ outFile.writeBytes(buffer.toByteArray())
+ buffer.reset()
+ val fileKey = "${ConnectivityDiagnosticsCollector::class.qualifiedName}_$filename"
+ testData.addFileMetric(fileKey, outFile)
+ }
+
+ /**
+ * Add connectivity diagnostics to the test data dump.
+ *
+ * <p>This collects a set of diagnostics that are relevant to connectivity test failures.
+ * <p>The dump will be collected immediately, and exported to a test artifact file when the
+ * test ends.
+ * @param exceptionContext An exception to write a stacktrace to the dump for context.
+ */
+ fun collectTestFailureDiagnostics(exceptionContext: Throwable? = null) {
+ collectDumpsysConnectivity(exceptionContext)
+ }
+
+ /**
+ * Add dumpsys connectivity to the test data dump.
+ *
+ * <p>The dump will be collected immediately, and exported to a test artifact file when the
+ * test ends.
+ * @param exceptionContext An exception to write a stacktrace to the dump for context.
+ */
+ fun collectDumpsysConnectivity(exceptionContext: Throwable? = null) {
+ Log.i(TAG, "Collecting dumpsys connectivity for test artifacts")
+ PrintWriter(buffer).let {
+ it.println("--- Dumpsys connectivity at ${ZonedDateTime.now()} ---")
+ maybeWriteExceptionContext(it, exceptionContext)
+ it.flush()
+ }
+ ParcelFileDescriptor.AutoCloseInputStream(
+ InstrumentationRegistry.getInstrumentation().uiAutomation.executeShellCommand(
+ "dumpsys connectivity --dump-priority HIGH")).use {
+ it.copyTo(buffer)
+ }
+ }
+
+ private fun maybeWriteExceptionContext(writer: PrintWriter, exceptionContext: Throwable?) {
+ if (exceptionContext == null) return
+ writer.println("At: ")
+ exceptionContext.printStackTrace(writer)
+ }
+}
\ No newline at end of file
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/MdnsTestUtils.kt b/staticlibs/testutils/devicetests/com/android/testutils/MdnsTestUtils.kt
index 8b88224..5729452 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/MdnsTestUtils.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/MdnsTestUtils.kt
@@ -28,8 +28,6 @@
import com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN
import com.android.net.module.util.NetworkStackConstants.UDP_HEADER_LEN
import com.android.net.module.util.TrackRecord
-import com.android.testutils.IPv6UdpFilter
-import com.android.testutils.TapPacketReader
import java.net.Inet6Address
import java.net.InetAddress
import kotlin.test.assertEquals
@@ -246,7 +244,7 @@
as Inet6Address
}
-fun TapPacketReader.pollForMdnsPacket(
+fun PollPacketReader.pollForMdnsPacket(
timeoutMs: Long = MDNS_REGISTRATION_TIMEOUT_MS,
predicate: (TestDnsPacket) -> Boolean
): TestDnsPacket? {
@@ -264,7 +262,7 @@
}
}
-fun TapPacketReader.pollForProbe(
+fun PollPacketReader.pollForProbe(
serviceName: String,
serviceType: String,
timeoutMs: Long = MDNS_REGISTRATION_TIMEOUT_MS
@@ -272,7 +270,7 @@
it.isProbeFor("$serviceName.$serviceType.local")
}
-fun TapPacketReader.pollForAdvertisement(
+fun PollPacketReader.pollForAdvertisement(
serviceName: String,
serviceType: String,
timeoutMs: Long = MDNS_REGISTRATION_TIMEOUT_MS
@@ -280,19 +278,19 @@
it.isReplyFor("$serviceName.$serviceType.local")
}
-fun TapPacketReader.pollForQuery(
+fun PollPacketReader.pollForQuery(
recordName: String,
vararg requiredTypes: Int,
timeoutMs: Long = MDNS_REGISTRATION_TIMEOUT_MS
): TestDnsPacket? = pollForMdnsPacket(timeoutMs) { it.isQueryFor(recordName, *requiredTypes) }
-fun TapPacketReader.pollForReply(
+fun PollPacketReader.pollForReply(
recordName: String,
type: Int,
timeoutMs: Long = MDNS_REGISTRATION_TIMEOUT_MS
): TestDnsPacket? = pollForMdnsPacket(timeoutMs) { it.isReplyFor(recordName, type) }
-fun TapPacketReader.pollForReply(
+fun PollPacketReader.pollForReply(
serviceName: String,
serviceType: String,
timeoutMs: Long = MDNS_REGISTRATION_TIMEOUT_MS
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/PacketResponder.kt b/staticlibs/testutils/devicetests/com/android/testutils/PacketResponder.kt
index 964c6c6..62d0e82 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/PacketResponder.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/PacketResponder.kt
@@ -21,24 +21,24 @@
private const val POLL_FREQUENCY_MS = 1000L
/**
- * A class that can be used to reply to packets from a [TapPacketReader].
+ * A class that can be used to reply to packets from a [PollPacketReader].
*
* A reply thread will be created to reply to incoming packets asynchronously.
- * The receiver creates a new read head on the [TapPacketReader], to read packets, so it does not
- * affect packets obtained through [TapPacketReader.popPacket].
+ * The receiver creates a new read head on the [PollPacketReader], to read packets, so it does not
+ * affect packets obtained through [PollPacketReader.popPacket].
*
- * @param reader a [TapPacketReader] to obtain incoming packets and reply to them.
+ * @param reader a [PollPacketReader] to obtain incoming packets and reply to them.
* @param packetFilter A filter to apply to incoming packets.
* @param name Name to use for the internal responder thread.
*/
abstract class PacketResponder(
- private val reader: TapPacketReader,
- private val packetFilter: Predicate<ByteArray>,
- name: String
+ private val reader: PollPacketReader,
+ private val packetFilter: Predicate<ByteArray>,
+ name: String
) {
private val replyThread = ReplyThread(name)
- protected abstract fun replyToPacket(packet: ByteArray, reader: TapPacketReader)
+ protected abstract fun replyToPacket(packet: ByteArray, reader: PollPacketReader)
/**
* Start the [PacketResponder].
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TapPacketReader.java b/staticlibs/testutils/devicetests/com/android/testutils/PollPacketReader.java
similarity index 91%
rename from staticlibs/testutils/devicetests/com/android/testutils/TapPacketReader.java
rename to staticlibs/testutils/devicetests/com/android/testutils/PollPacketReader.java
index b25b9f2..dbc7eb0 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/TapPacketReader.java
+++ b/staticlibs/testutils/devicetests/com/android/testutils/PollPacketReader.java
@@ -35,19 +35,19 @@
import kotlin.LazyKt;
/**
- * A packet reader that runs on a TAP interface.
+ * A packet reader that can poll for received packets and send responses on a fd.
*
* It also implements facilities to reply to received packets.
*/
-public class TapPacketReader extends PacketReader {
- private final FileDescriptor mTapFd;
+public class PollPacketReader extends PacketReader {
+ private final FileDescriptor mFd;
private final ArrayTrackRecord<byte[]> mReceivedPackets = new ArrayTrackRecord<>();
private final Lazy<ArrayTrackRecord<byte[]>.ReadHead> mReadHead =
LazyKt.lazy(mReceivedPackets::newReadHead);
- public TapPacketReader(Handler h, FileDescriptor tapFd, int maxPacketSize) {
+ public PollPacketReader(Handler h, FileDescriptor fd, int maxPacketSize) {
super(h, maxPacketSize);
- mTapFd = tapFd;
+ mFd = fd;
}
@@ -63,7 +63,7 @@
@Override
protected FileDescriptor createFd() {
- return mTapFd;
+ return mFd;
}
@Override
@@ -119,7 +119,7 @@
}
/*
- * Send a response on the TAP interface.
+ * Send a response on the fd.
*
* The passed ByteBuffer is flipped after use.
*
@@ -127,7 +127,7 @@
* @throws IOException if the interface can't be written to.
*/
public void sendResponse(final ByteBuffer packet) throws IOException {
- try (FileOutputStream out = new FileOutputStream(mTapFd)) {
+ try (FileOutputStream out = new FileOutputStream(mFd)) {
byte[] packetBytes = new byte[packet.limit()];
packet.get(packetBytes);
packet.flip(); // So we can reuse it in the future.
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java
index 51d57bc..6709555 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java
+++ b/staticlibs/testutils/devicetests/com/android/testutils/RouterAdvertisementResponder.java
@@ -62,18 +62,18 @@
private static final String TAG = "RouterAdvertisementResponder";
private static final Inet6Address DNS_SERVER =
(Inet6Address) InetAddresses.parseNumericAddress("2001:4860:4860::64");
- private final TapPacketReader mPacketReader;
+ private final PollPacketReader mPacketReader;
// Maps IPv6 address to MacAddress and isRouter boolean.
private final Map<Inet6Address, Pair<MacAddress, Boolean>> mNeighborMap = new ArrayMap<>();
private final IpPrefix mPrefix;
- public RouterAdvertisementResponder(TapPacketReader packetReader, IpPrefix prefix) {
+ public RouterAdvertisementResponder(PollPacketReader packetReader, IpPrefix prefix) {
super(packetReader, RouterAdvertisementResponder::isRsOrNs, TAG);
mPacketReader = packetReader;
mPrefix = Objects.requireNonNull(prefix);
}
- public RouterAdvertisementResponder(TapPacketReader packetReader) {
+ public RouterAdvertisementResponder(PollPacketReader packetReader) {
this(packetReader, makeRandomPrefix());
}
@@ -148,7 +148,7 @@
buildSllaOption(srcMac));
}
- private static void sendResponse(TapPacketReader reader, ByteBuffer buffer) {
+ private static void sendResponse(PollPacketReader reader, ByteBuffer buffer) {
try {
reader.sendResponse(buffer);
} catch (IOException e) {
@@ -158,7 +158,7 @@
}
}
- private void replyToRouterSolicitation(TapPacketReader reader, MacAddress dstMac) {
+ private void replyToRouterSolicitation(PollPacketReader reader, MacAddress dstMac) {
for (Map.Entry<Inet6Address, Pair<MacAddress, Boolean>> it : mNeighborMap.entrySet()) {
final boolean isRouter = it.getValue().second;
if (!isRouter) {
@@ -169,7 +169,7 @@
}
}
- private void replyToNeighborSolicitation(TapPacketReader reader, MacAddress dstMac,
+ private void replyToNeighborSolicitation(PollPacketReader reader, MacAddress dstMac,
Inet6Address dstIp, Inet6Address targetIp) {
final Pair<MacAddress, Boolean> neighbor = mNeighborMap.get(targetIp);
if (neighbor == null) {
@@ -190,7 +190,7 @@
}
@Override
- protected void replyToPacket(byte[] packet, TapPacketReader reader) {
+ protected void replyToPacket(byte[] packet, PollPacketReader reader) {
final ByteBuffer buf = ByteBuffer.wrap(packet);
// Messages are filtered by parent class, so it is safe to assume that packet is either an
// RS or NS.
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/TapPacketReaderRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/TapPacketReaderRule.kt
index 701666c..adf7619 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/TapPacketReaderRule.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/TapPacketReaderRule.kt
@@ -31,9 +31,9 @@
private const val HANDLER_TIMEOUT_MS = 10_000L
/**
- * A [TestRule] that sets up a [TapPacketReader] on a [TestNetworkInterface] for use in the test.
+ * A [TestRule] that sets up a [PollPacketReader] on a [TestNetworkInterface] for use in the test.
*
- * @param maxPacketSize Maximum size of packets read in the [TapPacketReader] buffer.
+ * @param maxPacketSize Maximum size of packets read in the [PollPacketReader] buffer.
* @param autoStart Whether to initialize the interface and start the reader automatically for every
* test. If false, each test must either call start() and stop(), or be annotated
* with TapPacketReaderTest before using the reader or interface.
@@ -50,21 +50,21 @@
// referenced before they could be initialized (typically if autoStart is false and the test
// does not call start or use @TapPacketReaderTest).
lateinit var iface: TestNetworkInterface
- lateinit var reader: TapPacketReader
+ lateinit var reader: PollPacketReader
@Volatile
private var readerRunning = false
/**
* Indicates that the [TapPacketReaderRule] should initialize its [TestNetworkInterface] and
- * start the [TapPacketReader] before the test, and tear them down afterwards.
+ * start the [PollPacketReader] before the test, and tear them down afterwards.
*
* For use when [TapPacketReaderRule] is created with autoStart = false.
*/
annotation class TapPacketReaderTest
/**
- * Initialize the tap interface and start the [TapPacketReader].
+ * Initialize the tap interface and start the [PollPacketReader].
*
* Tests using this method must also call [stop] before exiting.
* @param handler Handler to run the reader on. Callers are responsible for safely terminating
@@ -85,13 +85,13 @@
}
val usedHandler = handler ?: HandlerThread(
TapPacketReaderRule::class.java.simpleName).apply { start() }.threadHandler
- reader = TapPacketReader(usedHandler, iface.fileDescriptor.fileDescriptor, maxPacketSize)
+ reader = PollPacketReader(usedHandler, iface.fileDescriptor.fileDescriptor, maxPacketSize)
reader.startAsyncForTest()
readerRunning = true
}
/**
- * Stop the [TapPacketReader].
+ * Stop the [PollPacketReader].
*
* Tests calling [start] must call this method before exiting. If a handler was specified in
* [start], all messages on that handler must also be processed after calling this method and
diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt
index 9f28234..dcd422c 100644
--- a/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt
+++ b/staticlibs/testutils/hostdevice/com/android/testutils/Cleanup.kt
@@ -20,6 +20,7 @@
import com.android.testutils.FunctionalUtils.ThrowingRunnable
import com.android.testutils.FunctionalUtils.ThrowingSupplier
+import java.util.function.Consumer
import javax.annotation.CheckReturnValue
/**
@@ -73,11 +74,23 @@
* });
*/
+object TryTestConfig {
+ internal var diagnosticsCollector: Consumer<Throwable>? = null
+
+ /**
+ * Set the diagnostics collector to be used in case of failure in [tryTest].
+ */
+ fun setDiagnosticsCollector(collector: Consumer<Throwable>) {
+ diagnosticsCollector = collector
+ }
+}
+
@CheckReturnValue
fun <T> tryTest(block: () -> T) = TryExpr(
try {
Result.success(block())
} catch (e: Throwable) {
+ TryTestConfig.diagnosticsCollector?.accept(e)
Result.failure(e)
})
diff --git a/tests/common/Android.bp b/tests/common/Android.bp
index e95a81a..920492f 100644
--- a/tests/common/Android.bp
+++ b/tests/common/Android.bp
@@ -78,7 +78,7 @@
name: "ConnectivityCoverageTestsLib",
min_sdk_version: "30",
static_libs: [
- "FrameworksNetTestsLib",
+ "ConnectivityUnitTestsLib",
"NetdStaticLibTestsLib",
"NetworkStaticLibTestsLib",
"NetworkStackTestsLib",
diff --git a/tests/cts/net/AndroidTestTemplate.xml b/tests/cts/net/AndroidTestTemplate.xml
index 24431a6..a65316f 100644
--- a/tests/cts/net/AndroidTestTemplate.xml
+++ b/tests/cts/net/AndroidTestTemplate.xml
@@ -56,7 +56,13 @@
the runner will only run the tests annotated with that annotation, but if it does not,
the runner will run all the tests. -->
<option name="include-annotation" value="com.android.testutils.filters.{MODULE}" />
+ <option name="device-listeners" value="com.android.testutils.ConnectivityDiagnosticsCollector" />
</test>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <!-- Pattern matching the fileKey used by ConnectivityDiagnosticsCollector when calling addFileMetric -->
+ <option name="pull-pattern-keys" value="com.android.testutils.ConnectivityDiagnosticsCollector.*"/>
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
<!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if
one of the Mainline modules below is present on the device used for testing. -->
<object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 041e6cb..1de4cf9 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -71,7 +71,7 @@
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.RouterAdvertisementResponder
import com.android.testutils.SC_V2
-import com.android.testutils.TapPacketReader
+import com.android.testutils.PollPacketReader
import com.android.testutils.TestableNetworkAgent
import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnDscpPolicyStatusUpdated
import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated
@@ -135,7 +135,7 @@
private lateinit var srcAddressV6: Inet6Address
private lateinit var iface: TestNetworkInterface
private lateinit var tunNetworkCallback: TestNetworkCallback
- private lateinit var reader: TapPacketReader
+ private lateinit var reader: PollPacketReader
private lateinit var arpResponder: ArpResponder
private lateinit var raResponder: RouterAdvertisementResponder
@@ -169,7 +169,7 @@
}
handlerThread.start()
- reader = TapPacketReader(
+ reader = PollPacketReader(
handlerThread.threadHandler,
iface.fileDescriptor.fileDescriptor,
MAX_PACKET_LENGTH)
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index 61ebd8f..1e2a212 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -72,7 +72,7 @@
import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
import com.android.testutils.RecorderCallback.CallbackEntry.Lost
import com.android.testutils.RouterAdvertisementResponder
-import com.android.testutils.TapPacketReader
+import com.android.testutils.PollPacketReader
import com.android.testutils.TestableNetworkCallback
import com.android.testutils.assertThrows
import com.android.testutils.runAsShell
@@ -151,7 +151,7 @@
hasCarrier: Boolean
) {
private val tapInterface: TestNetworkInterface
- private val packetReader: TapPacketReader
+ private val packetReader: PollPacketReader
private val raResponder: RouterAdvertisementResponder
private val tnm: TestNetworkManager
val name get() = tapInterface.interfaceName
@@ -169,7 +169,11 @@
tnm.createTapInterface(hasCarrier, false /* bringUp */)
}
val mtu = tapInterface.mtu
- packetReader = TapPacketReader(handler, tapInterface.fileDescriptor.fileDescriptor, mtu)
+ packetReader = PollPacketReader(
+ handler,
+ tapInterface.fileDescriptor.fileDescriptor,
+ mtu
+ )
raResponder = RouterAdvertisementResponder(packetReader)
val iidString = "fe80::${Integer.toHexString(Random().nextInt(65536))}"
val linklocal = InetAddresses.parseNumericAddress(iidString) as Inet6Address
@@ -336,7 +340,7 @@
}
}
- private fun isEthernetSupported() : Boolean {
+ private fun isEthernetSupported(): Boolean {
return context.getSystemService(EthernetManager::class.java) != null
}
diff --git a/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java b/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java
index 2315940..11fc6df 100644
--- a/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java
@@ -115,6 +115,8 @@
private static final int NETWORK_TAG = 0xf00d;
private static final long THRESHOLD_BYTES = 2 * 1024 * 1024; // 2 MB
+ private static final long SHORT_TOLERANCE = MINUTE / 2;
+ private static final long LONG_TOLERANCE = MINUTE * 120;
private abstract class NetworkInterfaceToTest {
private boolean mMetered;
@@ -364,16 +366,17 @@
}
}
- private boolean shouldTestThisNetworkType(int networkTypeIndex, final long tolerance)
+ private boolean shouldTestThisNetworkType(int networkTypeIndex) {
+ return mPm.hasSystemFeature(mNetworkInterfacesToTest[networkTypeIndex].getSystemFeature());
+ }
+
+ private void requestNetworkAndGenerateTraffic(int networkTypeIndex, final long tolerance)
throws Exception {
- boolean hasFeature = mPm.hasSystemFeature(
- mNetworkInterfacesToTest[networkTypeIndex].getSystemFeature());
- if (!hasFeature) {
- return false;
- }
- NetworkCallback callback = new NetworkCallback(tolerance, new URL(CHECK_CONNECTIVITY_URL));
+ final NetworkInterfaceToTest networkInterface = mNetworkInterfacesToTest[networkTypeIndex];
+ final NetworkCallback callback = new NetworkCallback(tolerance,
+ new URL(CHECK_CONNECTIVITY_URL));
mCm.requestNetwork(new NetworkRequest.Builder()
- .addTransportType(mNetworkInterfacesToTest[networkTypeIndex].getTransportType())
+ .addTransportType(networkInterface.getTransportType())
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build(), callback);
synchronized (this) {
@@ -388,20 +391,17 @@
}
}
mCm.unregisterNetworkCallback(callback);
- if (callback.success) {
- mNetworkInterfacesToTest[networkTypeIndex].setMetered(callback.metered);
- mNetworkInterfacesToTest[networkTypeIndex].setRoaming(callback.roaming);
- mNetworkInterfacesToTest[networkTypeIndex].setIsDefault(callback.isDefault);
- return true;
+ if (!callback.success) {
+ fail(networkInterface.getSystemFeature()
+ + " is a reported system feature, however no corresponding "
+ + "connected network interface was found or the attempt "
+ + "to connect and read has timed out (timeout = " + (TIMEOUT_MILLIS * 2.4)
+ + "ms)." + networkInterface.getErrorMessage());
}
- // This will always fail at this point as we know 'hasFeature' is true.
- assertFalse(mNetworkInterfacesToTest[networkTypeIndex].getSystemFeature()
- + " is a reported system feature, "
- + "however no corresponding connected network interface was found or the attempt "
- + "to connect and read has timed out (timeout = " + (TIMEOUT_MILLIS * 2) + "ms)."
- + mNetworkInterfacesToTest[networkTypeIndex].getErrorMessage(), hasFeature);
- return false;
+ networkInterface.setMetered(callback.metered);
+ networkInterface.setRoaming(callback.roaming);
+ networkInterface.setIsDefault(callback.isDefault);
}
private String getSubscriberId(int networkIndex) {
@@ -417,9 +417,10 @@
@Test
public void testDeviceSummary() throws Exception {
for (int i = 0; i < mNetworkInterfacesToTest.length; ++i) {
- if (!shouldTestThisNetworkType(i, MINUTE / 2)) {
+ if (!shouldTestThisNetworkType(i)) {
continue;
}
+ requestNetworkAndGenerateTraffic(i, SHORT_TOLERANCE);
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
NetworkStats.Bucket bucket = null;
try {
@@ -453,9 +454,10 @@
@Test
public void testUserSummary() throws Exception {
for (int i = 0; i < mNetworkInterfacesToTest.length; ++i) {
- if (!shouldTestThisNetworkType(i, MINUTE / 2)) {
+ if (!shouldTestThisNetworkType(i)) {
continue;
}
+ requestNetworkAndGenerateTraffic(i, SHORT_TOLERANCE);
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
NetworkStats.Bucket bucket = null;
try {
@@ -489,14 +491,15 @@
@Test
public void testAppSummary() throws Exception {
for (int i = 0; i < mNetworkInterfacesToTest.length; ++i) {
+ if (!shouldTestThisNetworkType(i)) {
+ continue;
+ }
// Use tolerance value that large enough to make sure stats of at
// least one bucket is included. However, this is possible that
// the test will see data of different app but with the same UID
// that created before testing.
// TODO: Consider query stats before testing and use the difference to verify.
- if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
- continue;
- }
+ requestNetworkAndGenerateTraffic(i, LONG_TOLERANCE);
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
NetworkStats result = null;
try {
@@ -565,10 +568,11 @@
@Test
public void testAppDetails() throws Exception {
for (int i = 0; i < mNetworkInterfacesToTest.length; ++i) {
- // Relatively large tolerance to accommodate for history bucket size.
- if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
+ if (!shouldTestThisNetworkType(i)) {
continue;
}
+ // Relatively large tolerance to accommodate for history bucket size.
+ requestNetworkAndGenerateTraffic(i, LONG_TOLERANCE);
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
NetworkStats result = null;
try {
@@ -609,9 +613,10 @@
public void testUidDetails() throws Exception {
for (int i = 0; i < mNetworkInterfacesToTest.length; ++i) {
// Relatively large tolerance to accommodate for history bucket size.
- if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
+ if (!shouldTestThisNetworkType(i)) {
continue;
}
+ requestNetworkAndGenerateTraffic(i, LONG_TOLERANCE);
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
NetworkStats result = null;
try {
@@ -663,9 +668,10 @@
public void testTagDetails() throws Exception {
for (int i = 0; i < mNetworkInterfacesToTest.length; ++i) {
// Relatively large tolerance to accommodate for history bucket size.
- if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
+ if (!shouldTestThisNetworkType(i)) {
continue;
}
+ requestNetworkAndGenerateTraffic(i, LONG_TOLERANCE);
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
NetworkStats result = null;
try {
@@ -769,10 +775,11 @@
@Test
public void testUidTagStateDetails() throws Exception {
for (int i = 0; i < mNetworkInterfacesToTest.length; ++i) {
- // Relatively large tolerance to accommodate for history bucket size.
- if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
+ if (!shouldTestThisNetworkType(i)) {
continue;
}
+ // Relatively large tolerance to accommodate for history bucket size.
+ requestNetworkAndGenerateTraffic(i, LONG_TOLERANCE);
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
NetworkStats result = null;
try {
@@ -847,9 +854,10 @@
public void testCallback() throws Exception {
for (int i = 0; i < mNetworkInterfacesToTest.length; ++i) {
// Relatively large tolerance to accommodate for history bucket size.
- if (!shouldTestThisNetworkType(i, MINUTE / 2)) {
+ if (!shouldTestThisNetworkType(i)) {
continue;
}
+ requestNetworkAndGenerateTraffic(i, SHORT_TOLERANCE);
setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
TestUsageCallback usageCallback = new TestUsageCallback();
diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt
index f9acb66..aad072c 100644
--- a/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt
@@ -46,7 +46,7 @@
import com.android.testutils.DhcpClientPacketFilter
import com.android.testutils.DhcpOptionFilter
import com.android.testutils.RecorderCallback.CallbackEntry
-import com.android.testutils.TapPacketReader
+import com.android.testutils.PollPacketReader
import com.android.testutils.TestHttpServer
import com.android.testutils.TestableNetworkCallback
import com.android.testutils.runAsShell
@@ -93,7 +93,7 @@
private val ethRequestCb = TestableNetworkCallback()
private lateinit var iface: TestNetworkInterface
- private lateinit var reader: TapPacketReader
+ private lateinit var reader: PollPacketReader
private lateinit var capportUrl: Uri
private var testSkipped = false
@@ -118,7 +118,7 @@
iface = testInterfaceRule.createTapInterface()
handlerThread.start()
- reader = TapPacketReader(
+ reader = PollPacketReader(
handlerThread.threadHandler,
iface.fileDescriptor.fileDescriptor,
MAX_PACKET_LENGTH)
@@ -218,7 +218,7 @@
TEST_MTU, false /* rapidCommit */, capportUrl.toString())
}
-private fun <T : DhcpPacket> TapPacketReader.assertDhcpPacketReceived(
+private fun <T : DhcpPacket> PollPacketReader.assertDhcpPacketReceived(
packetType: Class<T>,
timeoutMs: Long,
type: Byte
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index c71d925..ad6fe63 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -100,7 +100,7 @@
import com.android.testutils.NsdServiceInfoCallbackRecord.ServiceInfoCallbackEvent.UnregisterCallbackSucceeded
import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
-import com.android.testutils.TapPacketReader
+import com.android.testutils.PollPacketReader
import com.android.testutils.TestDnsPacket
import com.android.testutils.TestableNetworkAgent
import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnNetworkCreated
@@ -1299,10 +1299,10 @@
val si = makeTestServiceInfo(testNetwork1.network)
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -1345,10 +1345,10 @@
parseNumericAddress("2001:db8::3"))
}
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -1391,10 +1391,10 @@
hostname = customHostname
}
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -1438,10 +1438,10 @@
val registrationRecord = NsdRegistrationRecord()
val discoveryRecord = NsdDiscoveryRecord()
val registeredService = registerService(registrationRecord, si)
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -1518,10 +1518,10 @@
val registrationRecord = NsdRegistrationRecord()
val discoveryRecord = NsdDiscoveryRecord()
val registeredService = registerService(registrationRecord, si)
- val packetReader = TapPacketReader(
+ val packetReader = PollPacketReader(
Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -1587,10 +1587,10 @@
val registrationRecord = NsdRegistrationRecord()
val discoveryRecord = NsdDiscoveryRecord()
val registeredService = registerService(registrationRecord, si)
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -1630,10 +1630,10 @@
fun testDiscoveryWithPtrOnlyResponse_ServiceIsFound() {
// Register service on testNetwork1
val discoveryRecord = NsdDiscoveryRecord()
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -1688,10 +1688,10 @@
fun testResolveWhenServerSendsNoAdditionalRecord() {
// Resolve service on testNetwork1
val resolveRecord = NsdResolveRecord()
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -1776,8 +1776,8 @@
var nsResponder: NSResponder? = null
tryTest {
registerService(registrationRecord, si)
- val packetReader = TapPacketReader(Handler(handlerThread.looper),
- testNetwork1.iface.fileDescriptor.fileDescriptor, 1500 /* maxPacketSize */)
+ val packetReader = PollPacketReader(Handler(handlerThread.looper),
+ testNetwork1.iface.fileDescriptor.fileDescriptor, 1500 /* maxPacketSize */)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -1826,7 +1826,7 @@
var nsResponder: NSResponder? = null
tryTest {
registerService(registrationRecord, si)
- val packetReader = TapPacketReader(Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor, 1500 /* maxPacketSize */)
packetReader.startAsyncForTest()
@@ -1916,7 +1916,7 @@
var nsResponder: NSResponder? = null
tryTest {
registerService(registrationRecord, si)
- val packetReader = TapPacketReader(Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor, 1500 /* maxPacketSize */)
packetReader.startAsyncForTest()
@@ -1991,10 +1991,10 @@
// Register service on testNetwork1
val discoveryRecord = NsdDiscoveryRecord()
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -2355,10 +2355,10 @@
it.port = TEST_PORT
it.publicKey = publicKey
}
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -2410,10 +2410,10 @@
parseNumericAddress("2001:db8::2"))
it.publicKey = publicKey
}
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -2467,10 +2467,10 @@
it.hostAddresses = listOf()
it.publicKey = publicKey
}
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
- testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
+ testNetwork1.iface.fileDescriptor.fileDescriptor,
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
@@ -2582,10 +2582,10 @@
"test_nsd_avoid_advertising_empty_txt_records",
"1"
)
- val packetReader = TapPacketReader(
- Handler(handlerThread.looper),
- testNetwork1.iface.fileDescriptor.fileDescriptor,
- 1500 /* maxPacketSize */
+ val packetReader = PollPacketReader(
+ Handler(handlerThread.looper),
+ testNetwork1.iface.fileDescriptor.fileDescriptor,
+ 1500 /* maxPacketSize */
)
packetReader.startAsyncForTest()
handlerThread.waitForIdle(TIMEOUT_MS)
diff --git a/tests/cts/net/util/java/android/net/cts/util/EthernetTestInterface.kt b/tests/cts/net/util/java/android/net/cts/util/EthernetTestInterface.kt
index 32d6899..20cfa1d 100644
--- a/tests/cts/net/util/java/android/net/cts/util/EthernetTestInterface.kt
+++ b/tests/cts/net/util/java/android/net/cts/util/EthernetTestInterface.kt
@@ -28,7 +28,7 @@
import android.os.Handler
import android.util.Log
import com.android.net.module.util.ArrayTrackRecord
-import com.android.testutils.TapPacketReader
+import com.android.testutils.PollPacketReader
import com.android.testutils.runAsShell
import com.android.testutils.waitForIdle
import java.net.NetworkInterface
@@ -85,7 +85,7 @@
assertNotNull(nif)
return nif.mtu
}
- val packetReader = TapPacketReader(handler, testIface.fileDescriptor.fileDescriptor, mtu)
+ val packetReader = PollPacketReader(handler, testIface.fileDescriptor.fileDescriptor, mtu)
private val listener = EthernetStateListener(name)
private val em = context.getSystemService(EthernetManager::class.java)!!
@Volatile private var cleanedUp = false
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 00f9d05..6892a42 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -72,8 +72,8 @@
],
}
-java_defaults {
- name: "FrameworksNetTestsDefaults",
+android_library {
+ name: "ConnectivityUnitTestsLib",
min_sdk_version: "30",
defaults: [
"framework-connectivity-internal-test-defaults",
@@ -82,6 +82,7 @@
"java/**/*.java",
"java/**/*.kt",
],
+ exclude_srcs: [":non-connectivity-module-test"],
static_libs: [
"androidx.test.rules",
"androidx.test.uiautomator_uiautomator",
@@ -110,14 +111,6 @@
"ServiceConnectivityResources",
],
exclude_kotlinc_generated_files: false,
-}
-
-android_library {
- name: "FrameworksNetTestsLib",
- defaults: [
- "FrameworksNetTestsDefaults",
- ],
- exclude_srcs: [":non-connectivity-module-test"],
visibility: ["//packages/modules/Connectivity/tests:__subpackages__"],
}
@@ -137,7 +130,7 @@
java_genrule {
name: "frameworks-net-tests-lib-jarjar-gen",
tool_files: [
- ":FrameworksNetTestsLib{.jar}",
+ ":ConnectivityUnitTestsLib{.jar}",
"jarjar-excludes.txt",
],
tools: [
@@ -145,7 +138,7 @@
],
out: ["frameworks-net-tests-lib-jarjar-rules.txt"],
cmd: "$(location jarjar-rules-generator) " +
- "$(location :FrameworksNetTestsLib{.jar}) " +
+ "$(location :ConnectivityUnitTestsLib{.jar}) " +
"--prefix android.net.connectivity " +
"--excludes $(location jarjar-excludes.txt) " +
"--output $(out)",
@@ -156,14 +149,25 @@
name: "FrameworksNetTests",
enabled: enable_frameworks_net_tests,
defaults: [
- "FrameworksNetTestsDefaults",
+ "framework-connectivity-internal-test-defaults",
"FrameworksNetTests-jni-defaults",
],
jarjar_rules: ":frameworks-net-tests-jarjar-rules",
+ srcs: [":non-connectivity-module-test"],
test_suites: ["device-tests"],
static_libs: [
+ "frameworks-base-testutils",
"services.core",
"services.net",
+ "androidx.test.rules",
+ "framework-protos",
+ "mockito-target-minus-junit4",
+ "net-tests-utils",
+ "service-connectivity-pre-jarjar",
+ "service-connectivity-tiramisu-pre-jarjar",
+ ],
+ libs: [
+ "android.test.mock.stubs",
],
jni_libs: [
"libandroid_net_connectivity_com_android_net_module_util_jni",
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
index 5c3ad22..efae244 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
@@ -22,21 +22,27 @@
import com.android.server.connectivity.mdns.MdnsConstants.FLAG_TRUNCATED
import com.android.server.connectivity.mdns.MdnsConstants.IPV4_SOCKET_ADDR
import com.android.server.connectivity.mdns.MdnsConstants.IPV6_SOCKET_ADDR
+import com.android.server.connectivity.mdns.MdnsInetAddressRecord
import com.android.server.connectivity.mdns.MdnsPacket
import com.android.server.connectivity.mdns.MdnsPacketReader
import com.android.server.connectivity.mdns.MdnsPointerRecord
import com.android.server.connectivity.mdns.MdnsRecord
+import com.android.server.connectivity.mdns.MdnsResponse
+import com.android.server.connectivity.mdns.MdnsServiceInfo
+import com.android.server.connectivity.mdns.MdnsServiceRecord
+import com.android.server.connectivity.mdns.MdnsTextRecord
import com.android.server.connectivity.mdns.util.MdnsUtils.createQueryDatagramPackets
import com.android.server.connectivity.mdns.util.MdnsUtils.truncateServiceName
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
-import java.net.DatagramPacket
-import kotlin.test.assertContentEquals
+import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
+import java.net.DatagramPacket
+import kotlin.test.assertContentEquals
@RunWith(DevSdkIgnoreRunner::class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
@@ -157,4 +163,54 @@
assertFalse(MdnsUtils.checkAllPacketsWithSameAddress(listOf(v6Packet, otherV6Packet)))
assertFalse(MdnsUtils.checkAllPacketsWithSameAddress(listOf(v4Packet, v6Packet)))
}
+
+ @Test
+ fun testBuildMdnsServiceInfoFromResponse() {
+ val serviceInstanceName = "MyTestService"
+ val serviceType = "_testservice._tcp.local"
+ val hostName = "Android_000102030405060708090A0B0C0D0E0F.local"
+ val port = 12345
+ val ttlTime = 120000L
+ val testElapsedRealtime = 123L
+ val serviceName = "$serviceInstanceName.$serviceType".split(".").toTypedArray()
+ val v4Address = "192.0.2.1"
+ val v6Address = "2001:db8::1"
+ val interfaceIndex = 99
+ val response = MdnsResponse(0 /* now */, serviceName, interfaceIndex, null /* network */)
+ // Set PTR record
+ response.addPointerRecord(MdnsPointerRecord(serviceType.split(".").toTypedArray(),
+ testElapsedRealtime, false /* cacheFlush */, ttlTime, serviceName))
+ // Set SRV record.
+ response.serviceRecord = MdnsServiceRecord(serviceName, testElapsedRealtime,
+ false /* cacheFlush */, ttlTime, 0 /* servicePriority */, 0 /* serviceWeight */,
+ port, hostName.split(".").toTypedArray())
+ // Set TXT record.
+ response.textRecord = MdnsTextRecord(serviceName,
+ testElapsedRealtime, true /* cacheFlush */, 0L /* ttlMillis */,
+ listOf(MdnsServiceInfo.TextEntry.fromString("somedifferent=entry")))
+ // Set InetAddress record.
+ response.addInet4AddressRecord(MdnsInetAddressRecord(hostName.split(".").toTypedArray(),
+ testElapsedRealtime, true /* cacheFlush */,
+ 0L /* ttlMillis */, InetAddresses.parseNumericAddress(v4Address)))
+ response.addInet6AddressRecord(MdnsInetAddressRecord(hostName.split(".").toTypedArray(),
+ testElapsedRealtime, true /* cacheFlush */,
+ 0L /* ttlMillis */, InetAddresses.parseNumericAddress(v6Address)))
+
+ // Convert a MdnsResponse to a MdnsServiceInfo
+ val serviceInfo = MdnsUtils.buildMdnsServiceInfoFromResponse(
+ response, serviceType.split(".").toTypedArray(), testElapsedRealtime)
+
+ assertEquals(serviceInstanceName, serviceInfo.serviceInstanceName)
+ assertArrayEquals(serviceType.split(".").toTypedArray(), serviceInfo.serviceType)
+ assertArrayEquals(hostName.split(".").toTypedArray(), serviceInfo.hostName)
+ assertEquals(port, serviceInfo.port)
+ assertEquals(1, serviceInfo.ipv4Addresses.size)
+ assertEquals(v4Address, serviceInfo.ipv4Addresses[0])
+ assertEquals(1, serviceInfo.ipv6Addresses.size)
+ assertEquals(v6Address, serviceInfo.ipv6Addresses[0])
+ assertEquals(interfaceIndex, serviceInfo.interfaceIndex)
+ assertEquals(null, serviceInfo.network)
+ assertEquals(mapOf("somedifferent" to "entry"),
+ serviceInfo.attributes)
+ }
}
diff --git a/thread/framework/java/android/net/thread/ThreadNetworkController.java b/thread/framework/java/android/net/thread/ThreadNetworkController.java
index bcef76c..14d22d1 100644
--- a/thread/framework/java/android/net/thread/ThreadNetworkController.java
+++ b/thread/framework/java/android/net/thread/ThreadNetworkController.java
@@ -423,11 +423,6 @@
@EphemeralKeyState int ephemeralKeyState,
String ephemeralKey,
long lifetimeMillis) {
- if (!Flags.epskcEnabled()) {
- throw new IllegalStateException(
- "This should not be called when Ephemeral key API is disabled");
- }
-
final long identity = Binder.clearCallingIdentity();
final Instant expiry =
ephemeralKeyState == EPHEMERAL_KEY_DISABLED
diff --git a/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java b/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java
index 3539331..cf7a4f7 100644
--- a/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java
+++ b/thread/tests/integration/src/android/net/thread/BorderRoutingTest.java
@@ -68,7 +68,7 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.testutils.TapPacketReader;
+import com.android.testutils.PollPacketReader;
import com.android.testutils.TestNetworkTracker;
import org.junit.After;
@@ -118,7 +118,7 @@
private Handler mHandler;
private TestNetworkTracker mInfraNetworkTracker;
private List<FullThreadDevice> mFtds;
- private TapPacketReader mInfraNetworkReader;
+ private PollPacketReader mInfraNetworkReader;
private InfraNetworkDevice mInfraDevice;
@Before
diff --git a/thread/tests/integration/src/android/net/thread/utils/InfraNetworkDevice.java b/thread/tests/integration/src/android/net/thread/utils/InfraNetworkDevice.java
index 72a278c..cb0c8ee 100644
--- a/thread/tests/integration/src/android/net/thread/utils/InfraNetworkDevice.java
+++ b/thread/tests/integration/src/android/net/thread/utils/InfraNetworkDevice.java
@@ -28,7 +28,7 @@
import com.android.net.module.util.Ipv6Utils;
import com.android.net.module.util.structs.LlaOption;
import com.android.net.module.util.structs.PrefixInformationOption;
-import com.android.testutils.TapPacketReader;
+import com.android.testutils.PollPacketReader;
import java.io.IOException;
import java.net.Inet6Address;
@@ -49,18 +49,18 @@
// The MAC address of this device.
public final MacAddress macAddr;
// The packet reader of the TUN interface of the test network.
- public final TapPacketReader packetReader;
+ public final PollPacketReader packetReader;
// The IPv6 address generated by SLAAC for the device.
public Inet6Address ipv6Addr;
/**
* Constructs an InfraNetworkDevice with the given {@link MAC address} and {@link
- * TapPacketReader}.
+ * PollPacketReader}.
*
* @param macAddr the MAC address of the device
* @param packetReader the packet reader of the TUN interface of the test network.
*/
- public InfraNetworkDevice(MacAddress macAddr, TapPacketReader packetReader) {
+ public InfraNetworkDevice(MacAddress macAddr, PollPacketReader packetReader) {
this.macAddr = macAddr;
this.packetReader = packetReader;
}
diff --git a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
index 7f31728..116fb72 100644
--- a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
+++ b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
@@ -47,7 +47,7 @@
import com.android.net.module.util.structs.Ipv6Header
import com.android.net.module.util.structs.PrefixInformationOption
import com.android.net.module.util.structs.RaHeader
-import com.android.testutils.TapPacketReader
+import com.android.testutils.PollPacketReader
import com.android.testutils.TestNetworkTracker
import com.android.testutils.initTestNetwork
import com.android.testutils.runAsShell
@@ -136,18 +136,18 @@
}
/**
- * Creates a [TapPacketReader] given the [TestNetworkInterface] and [Handler].
+ * Creates a [PollPacketReader] given the [TestNetworkInterface] and [Handler].
*
* @param testNetworkInterface the TUN interface of the test network
* @param handler the handler to process the packets
- * @return the [TapPacketReader]
+ * @return the [PollPacketReader]
*/
@JvmStatic
fun newPacketReader(
testNetworkInterface: TestNetworkInterface, handler: Handler
- ): TapPacketReader {
+ ): PollPacketReader {
val fd = testNetworkInterface.fileDescriptor.fileDescriptor
- val reader = TapPacketReader(handler, fd, testNetworkInterface.mtu)
+ val reader = PollPacketReader(handler, fd, testNetworkInterface.mtu)
handler.post { reader.start() }
handler.waitForIdle(timeoutMs = 5000)
return reader
@@ -191,7 +191,7 @@
}
/**
- * Polls for a packet from a given [TapPacketReader] that satisfies the `filter`.
+ * Polls for a packet from a given [PollPacketReader] that satisfies the `filter`.
*
* @param packetReader a TUN packet reader
* @param filter the filter to be applied on the packet
@@ -199,7 +199,7 @@
* than 3000ms to read the next packet, the method will return null
*/
@JvmStatic
- fun pollForPacket(packetReader: TapPacketReader, filter: Predicate<ByteArray>): ByteArray? {
+ fun pollForPacket(packetReader: PollPacketReader, filter: Predicate<ByteArray>): ByteArray? {
var packet: ByteArray?
while ((packetReader.poll(3000 /* timeoutMs */, filter).also { packet = it }) != null) {
return packet
@@ -570,10 +570,10 @@
@JvmStatic
@JvmOverloads
fun startInfraDeviceAndWaitForOnLinkAddr(
- tapPacketReader: TapPacketReader,
- macAddress: MacAddress = MacAddress.fromString("1:2:3:4:5:6")
+ pollPacketReader: PollPacketReader,
+ macAddress: MacAddress = MacAddress.fromString("1:2:3:4:5:6")
): InfraNetworkDevice {
- val infraDevice = InfraNetworkDevice(macAddress, tapPacketReader)
+ val infraDevice = InfraNetworkDevice(macAddress, pollPacketReader)
infraDevice.runSlaac(Duration.ofSeconds(60))
requireNotNull(infraDevice.ipv6Addr)
return infraDevice