diff options
-rw-r--r-- | common/moduleutils/Android.bp | 12 | ||||
-rw-r--r-- | tests/integration/src/android/net/ip/IpClientIntegrationTest.java | 92 | ||||
-rw-r--r-- | tests/lib/Android.bp | 4 | ||||
-rw-r--r-- | tests/lib/src/com/android/testutils/TapPacketReader.java | 76 |
4 files changed, 112 insertions, 72 deletions
diff --git a/common/moduleutils/Android.bp b/common/moduleutils/Android.bp index d0dd584..81475d2 100644 --- a/common/moduleutils/Android.bp +++ b/common/moduleutils/Android.bp @@ -62,3 +62,15 @@ filegroup { ], visibility: ["//frameworks/base/packages/Tethering"], } + +// Utility sources used by test libraries. +// This is its own group to limit indiscriminate dependency of test code on production code. +// TODO: move these classes and NetworkStack/tests/lib to frameworks/libs/net, and remove this. +filegroup { + name: "net-module-utils-srcs-for-tests", + visibility: ["//packages/modules/NetworkStack/tests/lib"], + srcs: [ + "src/android/net/util/FdEventsReader.java", + "src/android/net/util/PacketReader.java", + ], +} diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java index 97da9fb..0fa6266 100644 --- a/tests/integration/src/android/net/ip/IpClientIntegrationTest.java +++ b/tests/integration/src/android/net/ip/IpClientIntegrationTest.java @@ -109,19 +109,16 @@ import android.net.shared.ProvisioningConfiguration.ScanResultInfo; import android.net.util.InterfaceParams; import android.net.util.IpUtils; import android.net.util.NetworkStackUtils; -import android.net.util.PacketReader; import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; -import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemProperties; import android.system.ErrnoException; import android.system.Os; -import androidx.annotation.Nullable; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -134,6 +131,7 @@ import com.android.server.NetworkObserverRegistry; import com.android.server.NetworkStackService.NetworkStackServiceManager; import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService; import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.TapPacketReader; import org.junit.After; import org.junit.Before; @@ -145,7 +143,6 @@ import org.mockito.MockitoAnnotations; import org.mockito.Spy; import java.io.FileDescriptor; -import java.io.FileOutputStream; import java.io.IOException; import java.net.Inet4Address; import java.net.InetAddress; @@ -159,8 +156,6 @@ import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.Random; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; /** * Tests for IpClient. @@ -192,6 +187,7 @@ public class IpClientIntegrationTest { private HandlerThread mPacketReaderThread; private Handler mHandler; private TapPacketReader mPacketReader; + private FileDescriptor mTapFd; private IpClient mIpc; private Dependencies mDependencies; private byte[] mClientMac; @@ -238,46 +234,6 @@ public class IpClientIntegrationTest { }; private static final byte TEST_VENDOR_SPECIFIC_TYPE = 0x06; - private static class TapPacketReader extends PacketReader { - private final ParcelFileDescriptor mTapFd; - private final LinkedBlockingQueue<byte[]> mReceivedPackets = - new LinkedBlockingQueue<byte[]>(); - - TapPacketReader(Handler h, ParcelFileDescriptor tapFd) { - super(h, DATA_BUFFER_LEN); - mTapFd = tapFd; - } - - @Override - protected FileDescriptor createFd() { - return mTapFd.getFileDescriptor(); - } - - @Override - protected void handlePacket(byte[] recvbuf, int length) { - final byte[] newPacket = Arrays.copyOf(recvbuf, length); - try { - mReceivedPackets.put(newPacket); - } catch (InterruptedException e) { - fail("fail to put the new packet in the queue"); - } - } - - /** - * Get the next packet that was received on the interface. - * - */ - @Nullable - public byte[] popPacket(long timeoutMs) { - try { - return mReceivedPackets.poll(timeoutMs, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - // Fall through - } - return null; - } - } - private class Dependencies extends IpClient.Dependencies { private boolean mIsDhcpLeaseCacheEnabled; private boolean mIsDhcpRapidCommitEnabled; @@ -411,6 +367,7 @@ public class IpClientIntegrationTest { public void tearDown() throws Exception { if (mPacketReader != null) { mHandler.post(() -> mPacketReader.stop()); // Also closes the socket + mTapFd = null; } if (mPacketReaderThread != null) { mPacketReaderThread.quitSafely(); @@ -440,8 +397,8 @@ public class IpClientIntegrationTest { mPacketReaderThread.start(); mHandler = mPacketReaderThread.getThreadHandler(); - final ParcelFileDescriptor tapFd = iface.getFileDescriptor(); - mPacketReader = new TapPacketReader(mHandler, tapFd); + mTapFd = iface.getFileDescriptor().getFileDescriptor(); + mPacketReader = new TapPacketReader(mHandler, mTapFd, DATA_BUFFER_LEN); mHandler.post(() -> mPacketReader.start()); } @@ -532,21 +489,12 @@ public class IpClientIntegrationTest { false /* broadcast */, "duplicated request IP address"); } - private void sendResponse(final ByteBuffer packet) throws IOException { - try (FileOutputStream out = new FileOutputStream(mPacketReader.createFd())) { - byte[] packetBytes = new byte[packet.limit()]; - packet.get(packetBytes); - packet.flip(); // So we can reuse it in the future. - out.write(packetBytes); - } - } - private void sendArpReply(final byte[] clientMac) throws IOException { final ByteBuffer packet = ArpPacket.buildArpPacket(clientMac /* dst */, SERVER_MAC /* src */, INADDR_ANY.getAddress() /* target IP */, clientMac /* target HW address */, CLIENT_ADDR.getAddress() /* sender IP */, (short) ARP_REPLY); - sendResponse(packet); + mPacketReader.sendResponse(packet); } private void sendArpProbe() throws IOException { @@ -554,7 +502,7 @@ public class IpClientIntegrationTest { SERVER_MAC /* src */, CLIENT_ADDR.getAddress() /* target IP */, new byte[ETHER_ADDR_LEN] /* target HW address */, INADDR_ANY.getAddress() /* sender IP */, (short) ARP_REQUEST); - sendResponse(packet); + mPacketReader.sendResponse(packet); } private void startIpClientProvisioning(final boolean isDhcpLeaseCacheEnabled, @@ -667,18 +615,18 @@ public class IpClientIntegrationTest { packetList.add(packet); if (packet instanceof DhcpDiscoverPacket) { if (shouldReplyRapidCommitAck) { - sendResponse(buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu, + mPacketReader.sendResponse(buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu, true /* rapidCommit */, captivePortalApiUrl)); } else { - sendResponse(buildDhcpOfferPacket(packet, leaseTimeSec, (short) mtu, - captivePortalApiUrl)); + mPacketReader.sendResponse(buildDhcpOfferPacket(packet, leaseTimeSec, + (short) mtu, captivePortalApiUrl)); } } else if (packet instanceof DhcpRequestPacket) { final ByteBuffer byteBuffer = isSuccessLease ? buildDhcpAckPacket(packet, leaseTimeSec, (short) mtu, false /* rapidCommit */, captivePortalApiUrl) : buildDhcpNakPacket(packet); - sendResponse(byteBuffer); + mPacketReader.sendResponse(byteBuffer); } else { fail("invalid DHCP packet"); } @@ -777,7 +725,7 @@ public class IpClientIntegrationTest { assertEquals(NetworkInterface.getByName(mIfaceName).getMTU(), mtu); } - if (shouldRemoveTapInterface) removeTapInterface(mPacketReader.createFd()); + if (shouldRemoveTapInterface) removeTapInterface(mTapFd); try { mIpc.shutdown(); awaitIpClientShutdown(); @@ -845,12 +793,12 @@ public class IpClientIntegrationTest { final short mtu = (short) TEST_DEFAULT_MTU; if (!shouldReplyRapidCommitAck) { - sendResponse(buildDhcpOfferPacket(packet, TEST_LEASE_DURATION_S, mtu, + mPacketReader.sendResponse(buildDhcpOfferPacket(packet, TEST_LEASE_DURATION_S, mtu, null /* captivePortalUrl */)); packet = getNextDhcpPacket(); assertTrue(packet instanceof DhcpRequestPacket); } - sendResponse(buildDhcpAckPacket(packet, TEST_LEASE_DURATION_S, mtu, + mPacketReader.sendResponse(buildDhcpAckPacket(packet, TEST_LEASE_DURATION_S, mtu, shouldReplyRapidCommitAck, null /* captivePortalUrl */)); if (!shouldAbortPreconnection) { @@ -1126,7 +1074,7 @@ public class IpClientIntegrationTest { @Test public void testRestoreInitialInterfaceMtu_NotFoundInterfaceWhenStartingProvisioning() throws Exception { - removeTapInterface(mPacketReader.createFd()); + removeTapInterface(mTapFd); ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() .withoutIpReachabilityMonitor() .withoutIPv6() @@ -1284,7 +1232,7 @@ public class IpClientIntegrationTest { ByteBuffer ra = buildRaPacket(pio, rdnss1, rdnss2); waitForRouterSolicitation(); - sendResponse(ra); + mPacketReader.sendResponse(ra); ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); @@ -1299,7 +1247,7 @@ public class IpClientIntegrationTest { // If the RDNSS lifetime is above the minimum, the DNS server is accepted. rdnss1 = buildRdnssOption(68, lowlifeDnsServer); ra = buildRaPacket(pio, rdnss1, rdnss2); - sendResponse(ra); + mPacketReader.sendResponse(ra); verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(captor.capture()); lp = captor.getValue(); assertNotNull(lp); @@ -1312,7 +1260,7 @@ public class IpClientIntegrationTest { rdnss1 = buildRdnssOption(0, dnsServer); rdnss2 = buildRdnssOption(0, lowlifeDnsServer); ra = buildRaPacket(pio, rdnss1, rdnss2); - sendResponse(ra); + mPacketReader.sendResponse(ra); verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture()); lp = captor.getValue(); @@ -1546,8 +1494,8 @@ public class IpClientIntegrationTest { // Send Offer and handle Request -> Ack final String serverSentUrl = serverSendsOption ? TEST_CAPTIVE_PORTAL_URL : null; - sendResponse(buildDhcpOfferPacket(discover, TEST_LEASE_DURATION_S, (short) TEST_DEFAULT_MTU, - serverSentUrl)); + mPacketReader.sendResponse(buildDhcpOfferPacket(discover, TEST_LEASE_DURATION_S, + (short) TEST_DEFAULT_MTU, serverSentUrl)); final int testMtu = 1345; handleDhcpPackets(true /* isSuccessLease */, TEST_LEASE_DURATION_S, false /* isDhcpRapidCommitEnabled */, testMtu, diff --git a/tests/lib/Android.bp b/tests/lib/Android.bp index 249088f..d43243f 100644 --- a/tests/lib/Android.bp +++ b/tests/lib/Android.bp @@ -32,8 +32,12 @@ java_library { srcs: [ "src/**/*.java", "src/**/*.kt", + ":net-module-utils-srcs-for-tests", ], defaults: ["lib_mockito_extended"], + libs: [ + "androidx.annotation_annotation", + ], static_libs: [ "net-tests-utils-multivariant", ], diff --git a/tests/lib/src/com/android/testutils/TapPacketReader.java b/tests/lib/src/com/android/testutils/TapPacketReader.java new file mode 100644 index 0000000..c68e5a5 --- /dev/null +++ b/tests/lib/src/com/android/testutils/TapPacketReader.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 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.net.util.PacketReader; +import android.os.Handler; + +import androidx.annotation.Nullable; + +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class TapPacketReader extends PacketReader { + private final FileDescriptor mTapFd; + private final LinkedBlockingQueue<byte[]> mReceivedPackets = new LinkedBlockingQueue<byte[]>(); + + public TapPacketReader(Handler h, FileDescriptor tapFd, int maxPacketSize) { + super(h, maxPacketSize); + mTapFd = tapFd; + } + + @Override + protected FileDescriptor createFd() { + return mTapFd; + } + + @Override + protected void handlePacket(byte[] recvbuf, int length) { + final byte[] newPacket = Arrays.copyOf(recvbuf, length); + if (!mReceivedPackets.offer(newPacket)) { + throw new AssertionError("More than " + Integer.MAX_VALUE + " packets outstanding!"); + } + } + + /** + * Get the next packet that was received on the interface. + * + */ + @Nullable + public byte[] popPacket(long timeoutMs) { + try { + return mReceivedPackets.poll(timeoutMs, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + // Fall through + } + return null; + } + + public void sendResponse(final ByteBuffer packet) throws IOException { + try (FileOutputStream out = new FileOutputStream(mTapFd)) { + byte[] packetBytes = new byte[packet.limit()]; + packet.get(packetBytes); + packet.flip(); // So we can reuse it in the future. + out.write(packetBytes); + } + } +} |