Merge "Add method to destroy UDP socket" into main
diff --git a/framework/src/android/net/TestNetworkManager.java b/framework/src/android/net/TestNetworkManager.java
index 416c6de..cbc7a4f 100644
--- a/framework/src/android/net/TestNetworkManager.java
+++ b/framework/src/android/net/TestNetworkManager.java
@@ -23,8 +23,10 @@
import android.os.IBinder;
import android.os.RemoteException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.Objects;
/**
@@ -196,45 +198,6 @@
}
/**
- * Create a tap interface for testing purposes
- *
- * @param linkAddrs an array of LinkAddresses to assign to the TAP interface
- * @return A TestNetworkInterface representing the underlying TAP interface. Close the contained
- * ParcelFileDescriptor to tear down the TAP interface.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @NonNull
- public TestNetworkInterface createTapInterface(@NonNull LinkAddress[] linkAddrs) {
- try {
- return mService.createInterface(TAP, CARRIER_UP, BRING_UP, USE_IPV6_PROV_DELAY,
- linkAddrs, null /* iface */);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Create a tap interface for testing purposes
- *
- * @param bringUp whether to bring up the interface before returning it.
- *
- * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the
- * TAP interface.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @NonNull
- public TestNetworkInterface createTapInterface(boolean bringUp) {
- try {
- return mService.createInterface(TAP, CARRIER_UP, bringUp, USE_IPV6_PROV_DELAY,
- NO_ADDRS, null /* iface */);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Create a tap interface with a given interface name for testing purposes
*
* @param bringUp whether to bring up the interface before returning it.
@@ -258,26 +221,6 @@
}
/**
- * Create a tap interface with or without carrier for testing purposes.
- *
- * Note: setting carrierUp = false is not supported until kernel version 6.0.
- *
- * @param carrierUp whether the created interface has a carrier or not.
- * @param bringUp whether to bring up the interface before returning it.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @NonNull
- public TestNetworkInterface createTapInterface(boolean carrierUp, boolean bringUp) {
- try {
- return mService.createInterface(TAP, carrierUp, bringUp, USE_IPV6_PROV_DELAY, NO_ADDRS,
- null /* iface */);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Create a tap interface for testing purposes.
*
* Note: setting carrierUp = false is not supported until kernel version 6.0.
@@ -300,27 +243,6 @@
}
/**
- * Create a tap interface for testing purposes.
- *
- * @param disableIpv6ProvisioningDelay whether to disable DAD and RS delay.
- * @param linkAddrs an array of LinkAddresses to assign to the TAP interface
- * @return A TestNetworkInterface representing the underlying TAP interface. Close the contained
- * ParcelFileDescriptor to tear down the TAP interface.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @NonNull
- public TestNetworkInterface createTapInterface(boolean disableIpv6ProvisioningDelay,
- @NonNull LinkAddress[] linkAddrs) {
- try {
- return mService.createInterface(TAP, CARRIER_UP, BRING_UP, disableIpv6ProvisioningDelay,
- linkAddrs, null /* iface */);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Enable / disable carrier on TestNetworkInterface
*
* Note: TUNSETCARRIER is not supported until kernel version 5.0.
@@ -337,4 +259,110 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Represents a request to create a tun/tap interface for testing.
+ *
+ * @hide
+ */
+ public static class TestInterfaceRequest {
+ public final boolean isTun;
+ public final boolean hasCarrier;
+ public final boolean bringUp;
+ public final boolean disableIpv6ProvDelay;
+ @Nullable public final String ifname;
+ public final LinkAddress[] linkAddresses;
+
+ private TestInterfaceRequest(boolean isTun, boolean hasCarrier, boolean bringUp,
+ boolean disableProvDelay, @Nullable String ifname, LinkAddress[] linkAddresses) {
+ this.isTun = isTun;
+ this.hasCarrier = hasCarrier;
+ this.bringUp = bringUp;
+ this.disableIpv6ProvDelay = disableProvDelay;
+ this.ifname = ifname;
+ this.linkAddresses = linkAddresses;
+ }
+
+ /**
+ * Builder class for TestInterfaceRequest
+ *
+ * Defaults to a tap interface with carrier that has been brought up.
+ */
+ public static class Builder {
+ private boolean mIsTun = false;
+ private boolean mHasCarrier = true;
+ private boolean mBringUp = true;
+ private boolean mDisableIpv6ProvDelay = false;
+ @Nullable private String mIfname;
+ private List<LinkAddress> mLinkAddresses = new ArrayList<>();
+
+ /** Create tun interface. */
+ public Builder setTun() {
+ mIsTun = true;
+ return this;
+ }
+
+ /** Create tap interface. */
+ public Builder setTap() {
+ mIsTun = false;
+ return this;
+ }
+
+ /** Configure whether the interface has carrier. */
+ public Builder setHasCarrier(boolean hasCarrier) {
+ mHasCarrier = hasCarrier;
+ return this;
+ }
+
+ /** Configure whether the interface should be brought up. */
+ public Builder setBringUp(boolean bringUp) {
+ mBringUp = bringUp;
+ return this;
+ }
+
+ /** Disable DAD and RS delay. */
+ public Builder setDisableIpv6ProvisioningDelay(boolean disableProvDelay) {
+ mDisableIpv6ProvDelay = disableProvDelay;
+ return this;
+ }
+
+ /** Set the interface name. */
+ public Builder setInterfaceName(@Nullable String ifname) {
+ mIfname = ifname;
+ return this;
+ }
+
+ /** The addresses to configure on the interface. */
+ public Builder addLinkAddress(LinkAddress la) {
+ mLinkAddresses.add(la);
+ return this;
+ }
+
+ /** Build TestInterfaceRequest */
+ public TestInterfaceRequest build() {
+ return new TestInterfaceRequest(mIsTun, mHasCarrier, mBringUp,
+ mDisableIpv6ProvDelay, mIfname, mLinkAddresses.toArray(new LinkAddress[0]));
+ }
+ }
+ }
+
+ /**
+ * Create a TestNetworkInterface (tun or tap) for testing purposes.
+ *
+ * @param request The request describing the interface to create.
+ * @return A TestNetworkInterface representing the underlying tun/tap interface. Close the
+ * contained ParcelFileDescriptor to tear down the tun/tap interface.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
+ @NonNull
+ public TestNetworkInterface createTestInterface(@NonNull TestInterfaceRequest request) {
+ try {
+ // TODO: Make TestInterfaceRequest parcelable and pass it instead.
+ return mService.createInterface(request.isTun, request.hasCarrier, request.bringUp,
+ request.disableIpv6ProvDelay, request.linkAddresses, request.ifname);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/networksecurity/TEST_MAPPING b/networksecurity/TEST_MAPPING
index 448ee84..f75bf9a 100644
--- a/networksecurity/TEST_MAPPING
+++ b/networksecurity/TEST_MAPPING
@@ -1,4 +1,9 @@
{
+ "tethering-mainline-presubmit": [
+ {
+ "name": "NetworkSecurityUnitTests"
+ }
+ ],
"presubmit": [
{
"name": "CtsNetSecConfigCertificateTransparencyTestCases"
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 1212e29..d91bd11 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
@@ -564,7 +564,6 @@
// Never try mDNS on cellular, or on interfaces with incompatible flags
if (CollectionUtils.contains(transports, TRANSPORT_CELLULAR)
|| iface.isLoopback()
- || iface.isPointToPoint()
|| iface.isVirtual()
|| !iface.isUp()) {
return false;
diff --git a/service/native/libs/libclat/Android.bp b/service/native/libs/libclat/Android.bp
index 6c1c2c4..9554bd8 100644
--- a/service/native/libs/libclat/Android.bp
+++ b/service/native/libs/libclat/Android.bp
@@ -47,6 +47,7 @@
srcs: [
"clatutils_test.cpp",
],
+ stl: "libc++_static",
header_libs: [
"bpf_connectivity_headers",
],
diff --git a/service/src/com/android/server/L2capNetworkProvider.java b/service/src/com/android/server/L2capNetworkProvider.java
index 72bd858..814a068 100644
--- a/service/src/com/android/server/L2capNetworkProvider.java
+++ b/service/src/com/android/server/L2capNetworkProvider.java
@@ -58,8 +58,10 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.HandlerUtils;
import com.android.net.module.util.ServiceConnectivityJni;
import com.android.server.net.L2capNetwork;
+import com.android.server.net.L2capPacketForwarder;
import java.io.IOException;
import java.util.ArrayList;
@@ -75,7 +77,6 @@
// BLUETOOTH_CONNECT permission.
NetworkCapabilities.Builder.withoutDefaultCapabilities()
.addTransportType(TRANSPORT_BLUETOOTH)
- // TODO: remove NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED.
.addCapability(NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
.addCapability(NET_CAPABILITY_NOT_METERED)
@@ -226,6 +227,7 @@
}
private void destroyAndUnregisterReservedOffer(ReservedServerOffer reservedOffer) {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
// Ensure the offer still exists if this was posted on the handler.
if (!mReservedServerOffers.contains(reservedOffer)) return;
mReservedServerOffers.remove(reservedOffer);
@@ -237,13 +239,15 @@
@Nullable
private L2capNetwork createL2capNetwork(BluetoothSocket socket, NetworkCapabilities caps,
L2capNetwork.ICallback cb) {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
final String ifname = TUN_IFNAME + String.valueOf(sTunIndex++);
final ParcelFileDescriptor tunFd = mDeps.createTunInterface(ifname);
if (tunFd == null) {
return null;
}
- return L2capNetwork.create(mHandler, mContext, mProvider, ifname, socket, tunFd, caps, cb);
+ return L2capNetwork.create(
+ mHandler, mContext, mProvider, ifname, socket, tunFd, caps, mDeps, cb);
}
private static void closeBluetoothSocket(BluetoothSocket socket) {
@@ -269,22 +273,26 @@
private volatile boolean mIsRunning = true;
public AcceptThread(BluetoothServerSocket serverSocket) {
+ super("L2capNetworkProvider-AcceptThread");
mServerSocket = serverSocket;
}
private void postDestroyAndUnregisterReservedOffer() {
+ // Called on AcceptThread
mHandler.post(() -> {
destroyAndUnregisterReservedOffer(ReservedServerOffer.this);
});
}
private void postCreateServerNetwork(BluetoothSocket connectedSocket) {
+ // Called on AcceptThread
mHandler.post(() -> {
final boolean success = createServerNetwork(connectedSocket);
if (!success) closeBluetoothSocket(connectedSocket);
});
}
+ @Override
public void run() {
while (mIsRunning) {
final BluetoothSocket connectedSocket;
@@ -304,6 +312,7 @@
}
public void tearDown() {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
mIsRunning = false;
try {
// BluetoothServerSocket.close() is thread-safe.
@@ -320,6 +329,7 @@
}
private boolean createServerNetwork(BluetoothSocket socket) {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
// It is possible the offer went away.
if (!mReservedServerOffers.contains(this)) return false;
@@ -330,17 +340,19 @@
final L2capNetwork network = createL2capNetwork(socket, mReservedCapabilities,
new L2capNetwork.ICallback() {
- @Override
- public void onError(L2capNetwork network) {
- destroyAndUnregisterReservedOffer(ReservedServerOffer.this);
- }
- @Override
- public void onNetworkUnwanted(L2capNetwork network) {
- // Leave reservation in place.
- final boolean networkExists = mL2capNetworks.remove(network);
- if (!networkExists) return; // already torn down.
- network.tearDown();
- }
+ @Override
+ public void onError(L2capNetwork network) {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
+ destroyAndUnregisterReservedOffer(ReservedServerOffer.this);
+ }
+ @Override
+ public void onNetworkUnwanted(L2capNetwork network) {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
+ // Leave reservation in place.
+ final boolean networkExists = mL2capNetworks.remove(network);
+ if (!networkExists) return; // already torn down.
+ network.tearDown();
+ }
});
if (network == null) {
@@ -375,6 +387,7 @@
/** Called when the reservation goes away and the reserved offer must be torn down. */
public void tearDown() {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
mAcceptThread.tearDown();
for (L2capNetwork network : mL2capNetworks) {
network.tearDown();
@@ -424,10 +437,12 @@
private volatile boolean mIsAborted = false;
public ConnectThread(L2capNetworkSpecifier specifier, BluetoothSocket socket) {
+ super("L2capNetworkProvider-ConnectThread");
mSpecifier = specifier;
mSocket = socket;
}
+ @Override
public void run() {
try {
mSocket.connect();
@@ -447,6 +462,7 @@
}
public void abort() {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
mIsAborted = true;
// Closing the BluetoothSocket is the only way to unblock connect() because it calls
// shutdown on the underlying (connected) SOCK_SEQPACKET.
@@ -462,6 +478,7 @@
private boolean createClientNetwork(L2capNetworkSpecifier specifier,
BluetoothSocket socket) {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
// Check whether request still exists
final ClientRequestInfo cri = mClientNetworkRequests.get(specifier);
if (cri == null) return false;
@@ -472,18 +489,20 @@
final L2capNetwork network = createL2capNetwork(socket, caps,
new L2capNetwork.ICallback() {
- // TODO: do not send onUnavailable() after the network has become available. The
- // right thing to do here is to tearDown the network (if it still exists, because
- // note that the request might have already been removed in the meantime, so
- // `network` cannot be used directly.
- @Override
- public void onError(L2capNetwork network) {
- declareAllNetworkRequestsUnfulfillable(specifier);
- }
- @Override
- public void onNetworkUnwanted(L2capNetwork network) {
- declareAllNetworkRequestsUnfulfillable(specifier);
- }
+ // TODO: do not send onUnavailable() after the network has become available. The
+ // right thing to do here is to tearDown the network (if it still exists,
+ // because note that the request might have already been removed in the
+ // meantime, so `network` cannot be used directly.
+ @Override
+ public void onError(L2capNetwork network) {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
+ declareAllNetworkRequestsUnfulfillable(specifier);
+ }
+ @Override
+ public void onNetworkUnwanted(L2capNetwork network) {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
+ declareAllNetworkRequestsUnfulfillable(specifier);
+ }
});
if (network == null) return false;
@@ -595,6 +614,7 @@
* Only call this when all associated NetworkRequests have been released.
*/
private void releaseClientNetworkRequest(ClientRequestInfo cri) {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
mClientNetworkRequests.remove(cri.specifier);
if (cri.connectThread.isAlive()) {
// Note that if ConnectThread succeeds between calling #isAlive() and #abort(), the
@@ -610,6 +630,7 @@
}
private void declareAllNetworkRequestsUnfulfillable(L2capNetworkSpecifier specifier) {
+ HandlerUtils.ensureRunningOnHandlerThread(mHandler);
final ClientRequestInfo cri = mClientNetworkRequests.get(specifier);
if (cri == null) return;
@@ -629,6 +650,7 @@
return thread;
}
+ /** Create a tun interface configured for blocking i/o */
@Nullable
public ParcelFileDescriptor createTunInterface(String ifname) {
final ParcelFileDescriptor fd;
@@ -651,13 +673,19 @@
}
return fd;
}
+
+ /** Create an L2capPacketForwarder and start forwarding */
+ public L2capPacketForwarder createL2capPacketForwarder(Handler handler,
+ ParcelFileDescriptor tunFd, BluetoothSocket socket, boolean compressHeaders,
+ L2capPacketForwarder.ICallback cb) {
+ return new L2capPacketForwarder(handler, tunFd, socket, compressHeaders, cb);
+ }
}
public L2capNetworkProvider(Context context) {
this(new Dependencies(), context);
}
- @VisibleForTesting
public L2capNetworkProvider(Dependencies deps, Context context) {
mDeps = deps;
mContext = context;
diff --git a/service/src/com/android/server/net/L2capNetwork.java b/service/src/com/android/server/net/L2capNetwork.java
index b624bca..c7417f9 100644
--- a/service/src/com/android/server/net/L2capNetwork.java
+++ b/service/src/com/android/server/net/L2capNetwork.java
@@ -38,6 +38,8 @@
import android.os.ParcelFileDescriptor;
import android.util.Log;
+import com.android.server.L2capNetworkProvider;
+
public class L2capNetwork {
private static final NetworkScore NETWORK_SCORE = new NetworkScore.Builder().build();
private final String mLogTag;
@@ -115,7 +117,7 @@
public L2capNetwork(String logTag, Handler handler, Context context, NetworkProvider provider,
BluetoothSocket socket, ParcelFileDescriptor tunFd, NetworkCapabilities nc,
- LinkProperties lp, ICallback cb) {
+ LinkProperties lp, L2capNetworkProvider.Dependencies deps, ICallback cb) {
mLogTag = logTag;
mHandler = handler;
mNetworkCapabilities = nc;
@@ -123,7 +125,8 @@
final L2capNetworkSpecifier spec = (L2capNetworkSpecifier) nc.getNetworkSpecifier();
final boolean compressHeaders = spec.getHeaderCompression() == HEADER_COMPRESSION_6LOWPAN;
- mForwarder = new L2capPacketForwarder(handler, tunFd, socket, compressHeaders, () -> {
+ mForwarder = deps.createL2capPacketForwarder(handler, tunFd, socket, compressHeaders,
+ () -> {
// TODO: add a check that this callback is invoked on the handler thread.
cb.onError(L2capNetwork.this);
});
@@ -146,7 +149,7 @@
@Nullable
public static L2capNetwork create(Handler handler, Context context, NetworkProvider provider,
String ifname, BluetoothSocket socket, ParcelFileDescriptor tunFd,
- NetworkCapabilities nc, ICallback cb) {
+ NetworkCapabilities nc, L2capNetworkProvider.Dependencies deps, ICallback cb) {
// TODO: add a check that this function is invoked on the handler thread.
final String logTag = String.format("L2capNetwork[%s]", ifname);
@@ -157,7 +160,8 @@
final LinkProperties lp = new L2capIpClient(logTag, context, ifname).start();
if (lp == null) return null;
- return new L2capNetwork(logTag, handler, context, provider, socket, tunFd, nc, lp, cb);
+ return new L2capNetwork(
+ logTag, handler, context, provider, socket, tunFd, nc, lp, deps, cb);
}
/** Get the NetworkCapabilities used for this Network */
diff --git a/service/src/com/android/server/net/L2capPacketForwarder.java b/service/src/com/android/server/net/L2capPacketForwarder.java
index 00faecf..737cb9c 100644
--- a/service/src/com/android/server/net/L2capPacketForwarder.java
+++ b/service/src/com/android/server/net/L2capPacketForwarder.java
@@ -233,6 +233,7 @@
L2capThread(IReadWriteFd readFd, IReadWriteFd writeFd, boolean isIngress,
boolean compressHeaders) {
+ super("L2capNetworkProvider-ForwarderThread");
mLogTag = isIngress ? "L2capForwarderThread-Ingress" : "L2capForwarderThread-Egress";
mReadFd = readFd;
mWriteFd = writeFd;
diff --git a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
index 8e790ca..c6a1b09 100644
--- a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
+++ b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
@@ -19,8 +19,6 @@
package android.net.cts
-import android.Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG
-import android.Manifest.permission.WRITE_DEVICE_CONFIG
import android.content.pm.PackageManager.FEATURE_AUTOMOTIVE
import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.pm.PackageManager.FEATURE_WIFI
@@ -55,8 +53,6 @@
import android.os.SystemProperties
import android.os.UserManager
import android.platform.test.annotations.AppModeFull
-import android.provider.DeviceConfig
-import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY
import android.system.Os
import android.system.OsConstants
import android.system.OsConstants.AF_INET6
@@ -90,7 +86,6 @@
import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
import com.android.testutils.SkipPresubmit
import com.android.testutils.TestableNetworkCallback
-import com.android.testutils.runAsShell
import com.android.testutils.waitForIdle
import com.google.common.truth.Expect
import com.google.common.truth.Truth.assertThat
@@ -116,7 +111,6 @@
private const val TAG = "ApfIntegrationTest"
private const val TIMEOUT_MS = 2000L
-private const val APF_NEW_RA_FILTER_VERSION = "apf_new_ra_filter_version"
private const val POLLING_INTERVAL_MS: Int = 100
private const val RCV_BUFFER_SIZE = 1480
private const val PING_HEADER_LENGTH = 8
@@ -192,16 +186,6 @@
Thread.sleep(1000)
// TODO: check that there is no active wifi network. Otherwise, ApfFilter has already been
// created.
- // APF adb cmds are only implemented in ApfFilter.java. Enable experiment to prevent
- // LegacyApfFilter.java from being used.
- runAsShell(WRITE_DEVICE_CONFIG, WRITE_ALLOWLISTED_DEVICE_CONFIG) {
- DeviceConfig.setProperty(
- NAMESPACE_CONNECTIVITY,
- APF_NEW_RA_FILTER_VERSION,
- "1", // value => force enabled
- false // makeDefault
- )
- }
}
@AfterClass
diff --git a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
index 1de4cf9..ceccf0b 100644
--- a/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
+++ b/tests/cts/net/src/android/net/cts/DscpPolicyTest.kt
@@ -44,6 +44,7 @@
import android.net.RouteInfo
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
+import android.net.TestNetworkManager.TestInterfaceRequest
import android.net.cts.util.CtsNetUtils.TestNetworkCallback
import android.os.HandlerThread
import android.os.SystemClock
@@ -164,7 +165,11 @@
// Only statically configure the IPv4 address; for IPv6, use the SLAAC generated
// address.
- iface = tnm.createTapInterface(arrayOf(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN)))
+ val req = TestInterfaceRequest.Builder()
+ .setTap()
+ .addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, IP4_PREFIX_LEN))
+ .build()
+ iface = tnm.createTestInterface(req)
assertNotNull(iface)
}
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index 06f2075..9f32132 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -51,6 +51,7 @@
import android.net.StaticIpConfiguration
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
+import android.net.TestNetworkManager.TestInterfaceRequest
import android.net.cts.EthernetManagerTest.EthernetStateListener.CallbackEntry.EthernetStateChanged
import android.net.cts.EthernetManagerTest.EthernetStateListener.CallbackEntry.InterfaceStateChanged
import android.os.Build
@@ -169,7 +170,12 @@
// false, it is subsequently disabled. This means that the interface may briefly get
// link. With IPv6 provisioning delays (RS delay and DAD) disabled, this can cause
// tests that expect no network to come up when hasCarrier is false to become flaky.
- tnm.createTapInterface(hasCarrier, false /* bringUp */)
+ val req = TestInterfaceRequest.Builder()
+ .setTap()
+ .setHasCarrier(hasCarrier)
+ .setBringUp(false)
+ .build()
+ tnm.createTestInterface(req)
}
val mtu = tapInterface.mtu
packetReader = PollPacketReader(
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
index 1cc9985..f763bae 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
@@ -610,6 +610,7 @@
@Test
public void testSocketCreatedForMulticastInterface() throws Exception {
+ doReturn(true).when(mTestNetworkIfaceWrapper).isPointToPoint();
doReturn(true).when(mTestNetworkIfaceWrapper).supportsMulticast();
startMonitoringSockets();
@@ -621,18 +622,6 @@
}
@Test
- public void testNoSocketCreatedForPTPInterface() throws Exception {
- doReturn(true).when(mTestNetworkIfaceWrapper).isPointToPoint();
- startMonitoringSockets();
-
- final TestSocketCallback testCallback = new TestSocketCallback();
- runOnHandler(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback));
-
- postNetworkAvailable(TRANSPORT_BLUETOOTH);
- testCallback.expectedNoCallback();
- }
-
- @Test
public void testNoSocketCreatedForVPNInterface() throws Exception {
// VPN interfaces generally also have IFF_POINTOPOINT, but even if they don't, they should
// not be included even with TRANSPORT_WIFI.
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
index d44bd0a..489c3ad 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
@@ -20,42 +20,37 @@
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothServerSocket
import android.bluetooth.BluetoothSocket
-import android.content.Context
import android.net.L2capNetworkSpecifier
import android.net.L2capNetworkSpecifier.HEADER_COMPRESSION_6LOWPAN
import android.net.L2capNetworkSpecifier.HEADER_COMPRESSION_NONE
import android.net.L2capNetworkSpecifier.ROLE_SERVER
-import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
-import android.net.NetworkProvider
-import android.net.NetworkProvider.NetworkOfferCallback
import android.net.NetworkRequest
-import android.net.NetworkScore
import android.net.NetworkSpecifier
import android.os.Build
import android.os.HandlerThread
-import android.os.Looper
-import com.android.server.L2capNetworkProvider
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.RecorderCallback.CallbackEntry.Reserved
+import com.android.testutils.RecorderCallback.CallbackEntry.Unavailable
import com.android.testutils.TestableNetworkCallback
+import com.android.testutils.waitForIdle
import java.io.IOException
-import java.util.concurrent.Executor
+import java.util.Optional
import java.util.concurrent.LinkedBlockingQueue
import kotlin.test.assertEquals
+import kotlin.test.assertFalse
import kotlin.test.assertNull
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.doThrow
import org.mockito.Mockito.mock
-import org.mockito.MockitoAnnotations
private const val PSM = 0x85
private val REMOTE_MAC = byteArrayOf(1, 2, 3, 4, 5, 6)
@@ -67,14 +62,19 @@
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.R)
+@DevSdkIgnoreRunner.MonitorThreadLeak
class CSL2capProviderTest : CSTest() {
private val btAdapter = mock<BluetoothAdapter>()
private val btServerSocket = mock<BluetoothServerSocket>()
private val btSocket = mock<BluetoothSocket>()
private val providerDeps = mock<L2capNetworkProvider.Dependencies>()
- private val acceptQueue = LinkedBlockingQueue<BluetoothSocket>()
+ // BlockingQueue does not support put(null) operations, as null is used as an internal sentinel
+ // value. Therefore, use Optional<BluetoothSocket> where an empty optional signals the
+ // BluetoothServerSocket#close() operation.
+ private val acceptQueue = LinkedBlockingQueue<Optional<BluetoothSocket>>()
private val handlerThread = HandlerThread("CSL2capProviderTest thread").apply { start() }
+ private val registeredCallbacks = ArrayList<TestableNetworkCallback>()
// Requires Dependencies mock to be setup before creation.
private lateinit var provider: L2capNetworkProvider
@@ -83,15 +83,16 @@
fun innerSetUp() {
doReturn(btAdapter).`when`(bluetoothManager).getAdapter()
doReturn(btServerSocket).`when`(btAdapter).listenUsingInsecureL2capChannel()
- doReturn(PSM).`when`(btServerSocket).getPsm();
+ doReturn(PSM).`when`(btServerSocket).getPsm()
doAnswer {
val sock = acceptQueue.take()
- sock ?: throw IOException()
+ if (sock == null || !sock.isPresent()) throw IOException()
+ sock.get()
}.`when`(btServerSocket).accept()
doAnswer {
- acceptQueue.put(null)
+ acceptQueue.put(Optional.empty())
}.`when`(btServerSocket).close()
doReturn(handlerThread).`when`(providerDeps).getHandlerThread()
@@ -101,16 +102,30 @@
@After
fun innerTearDown() {
+ // Unregistering a callback which has previously been unregistered by virtue of receiving
+ // onUnavailable is a noop.
+ registeredCallbacks.forEach { cm.unregisterNetworkCallback(it) }
+ // Wait for CS handler idle, meaning the unregisterNetworkCallback has been processed and
+ // L2capNetworkProvider has been notified.
+ waitForIdle()
+
+ // While quitSafely() effectively waits for idle, it is not enough, because the tear down
+ // path itself posts on the handler thread. This means that waitForIdle() needs to run
+ // twice. The first time, to ensure all active threads have been joined, and the second time
+ // to run all associated clean up actions.
+ handlerThread.waitForIdle(HANDLER_TIMEOUT_MS)
handlerThread.quitSafely()
handlerThread.join()
}
private fun reserveNetwork(nr: NetworkRequest) = TestableNetworkCallback().also {
cm.reserveNetwork(nr, csHandler, it)
+ registeredCallbacks.add(it)
}
private fun requestNetwork(nr: NetworkRequest) = TestableNetworkCallback().also {
cm.requestNetwork(nr, it, csHandler)
+ registeredCallbacks.add(it)
}
private fun NetworkRequest.copyWithSpecifier(specifier: NetworkSpecifier): NetworkRequest {
@@ -188,4 +203,42 @@
nr = REQUEST.copyWithSpecifier(specifier)
reserveNetwork(nr).assertNoCallback()
}
+
+ @Test
+ fun testBluetoothException_listenUsingInsecureL2capChannelThrows() {
+ doThrow(IOException()).`when`(btAdapter).listenUsingInsecureL2capChannel()
+ var specifier = L2capNetworkSpecifier.Builder()
+ .setRole(ROLE_SERVER)
+ .setHeaderCompression(HEADER_COMPRESSION_6LOWPAN)
+ .build()
+ var nr = REQUEST.copyWithSpecifier(specifier)
+ reserveNetwork(nr).expect<Unavailable>()
+
+ doReturn(btServerSocket).`when`(btAdapter).listenUsingInsecureL2capChannel()
+ reserveNetwork(nr).expect<Reserved>()
+ }
+
+ @Test
+ fun testBluetoothException_acceptThrows() {
+ doThrow(IOException()).`when`(btServerSocket).accept()
+ var specifier = L2capNetworkSpecifier.Builder()
+ .setRole(ROLE_SERVER)
+ .setHeaderCompression(HEADER_COMPRESSION_6LOWPAN)
+ .build()
+ var nr = REQUEST.copyWithSpecifier(specifier)
+ val cb = reserveNetwork(nr)
+ cb.expect<Reserved>()
+ cb.expect<Unavailable>()
+
+ // BluetoothServerSocket#close() puts Optional.empty() on the acceptQueue.
+ acceptQueue.clear()
+ doAnswer {
+ val sock = acceptQueue.take()
+ assertFalse(sock.isPresent())
+ throw IOException() // to indicate the socket was closed.
+ }.`when`(btServerSocket).accept()
+ val cb2 = reserveNetwork(nr)
+ cb2.expect<Reserved>()
+ cb2.assertNoCallback()
+ }
}