Use ThreadLeakMonitor for CSL2capProviderTest
This CL introduces ThreadLeakMonitor for CSL2capProviderTest.
ThreadLeakMonitor ignores threads with unique names, so all
L2capNetworkProvider related threads must specify a name.
Test: TH
Change-Id: I7cfcc93ab562a1ada2058d8c73e968a8d0005b1d
diff --git a/service/src/com/android/server/L2capNetworkProvider.java b/service/src/com/android/server/L2capNetworkProvider.java
index 8201c39..f303cdc 100644
--- a/service/src/com/android/server/L2capNetworkProvider.java
+++ b/service/src/com/android/server/L2capNetworkProvider.java
@@ -273,6 +273,7 @@
private volatile boolean mIsRunning = true;
public AcceptThread(BluetoothServerSocket serverSocket) {
+ super("L2capNetworkProvider-AcceptThread");
mServerSocket = serverSocket;
}
@@ -436,6 +437,7 @@
private volatile boolean mIsAborted = false;
public ConnectThread(L2capNetworkSpecifier specifier, BluetoothSocket socket) {
+ super("L2capNetworkProvider-ConnectThread");
mSpecifier = specifier;
mSocket = socket;
}
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/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
index 4890f4b..7f4744b 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSL2capProviderTest.kt
@@ -43,6 +43,7 @@
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.Optional
import java.util.concurrent.Executor
@@ -71,6 +72,7 @@
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.R)
+@DevSdkIgnoreRunner.MonitorThreadLeak
class CSL2capProviderTest : CSTest() {
private val btAdapter = mock<BluetoothAdapter>()
private val btServerSocket = mock<BluetoothServerSocket>()
@@ -82,6 +84,7 @@
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
@@ -109,16 +112,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 {