Merge "Update TimerFileDescriptor to support different task types" into main am: 97a4977f83
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/3346505
Change-Id: Ib8bb188a61418a3c3b6e13ebd246b2e743c26fea
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/staticlibs/device/com/android/net/module/util/TimerFileDescriptor.java b/staticlibs/device/com/android/net/module/util/TimerFileDescriptor.java
index 5a16de6..dbbccc5 100644
--- a/staticlibs/device/com/android/net/module/util/TimerFileDescriptor.java
+++ b/staticlibs/device/com/android/net/module/util/TimerFileDescriptor.java
@@ -21,6 +21,7 @@
import android.os.Handler;
import android.os.Looper;
+import android.os.Message;
import android.os.MessageQueue;
import android.os.ParcelFileDescriptor;
import android.util.CloseGuard;
@@ -69,7 +70,61 @@
private final ParcelFileDescriptor mParcelFileDescriptor;
private final int mFdInt;
@Nullable
- private Runnable mTask;
+ private ITask mTask;
+
+ /**
+ * An interface for defining tasks that can be executed using a {@link Handler}.
+ */
+ public interface ITask {
+ /**
+ * Executes the task using the provided {@link Handler}.
+ *
+ * @param handler The {@link Handler} to use for executing the task.
+ */
+ void post(Handler handler);
+ }
+
+ /**
+ * A task that sends a {@link Message} using a {@link Handler}.
+ */
+ public static class MessageTask implements ITask {
+ private final Message mMessage;
+
+ public MessageTask(Message message) {
+ mMessage = message;
+ }
+
+ /**
+ * Sends the {@link Message} using the provided {@link Handler}.
+ *
+ * @param handler The {@link Handler} to use for sending the message.
+ */
+ @Override
+ public void post(Handler handler) {
+ handler.sendMessage(mMessage);
+ }
+ }
+
+ /**
+ * A task that posts a {@link Runnable} to a {@link Handler}.
+ */
+ public static class RunnableTask implements ITask {
+ private final Runnable mRunnable;
+
+ public RunnableTask(Runnable runnable) {
+ mRunnable = runnable;
+ }
+
+ /**
+ * Posts the {@link Runnable} to the provided {@link Handler}.
+ *
+ * @param handler The {@link Handler} to use for posting the runnable.
+ */
+ @Override
+ public void post(Handler handler) {
+ handler.post(mRunnable);
+ }
+ }
/**
* TimerFileDescriptor constructor
@@ -98,13 +153,13 @@
* @throws IllegalArgumentException if try to replace the current scheduled task
* @throws IllegalArgumentException if the delay time is less than 0
*/
- public void setDelayedTask(@NonNull Runnable task, long delayMs) {
+ public void setDelayedTask(@NonNull ITask task, long delayMs) {
ensureRunningOnCorrectThread();
if (mTask != null) {
throw new IllegalArgumentException("task is already scheduled");
}
if (delayMs <= 0L) {
- mHandler.post(task);
+ task.post(mHandler);
return;
}
@@ -163,7 +218,7 @@
private void handleExpiration() {
// Execute the task
if (mTask != null) {
- mTask.run();
+ mTask.post(mHandler);
mTask = null;
}
}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/TimerFileDescriptorTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/TimerFileDescriptorTest.kt
index 2018902..f5e47c9 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/TimerFileDescriptorTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/TimerFileDescriptorTest.kt
@@ -20,7 +20,12 @@
import android.os.ConditionVariable
import android.os.Handler
import android.os.HandlerThread
+import android.os.Looper
+import android.os.Message
import androidx.test.filters.SmallTest
+import com.android.net.module.util.TimerFileDescriptor.ITask
+import com.android.net.module.util.TimerFileDescriptor.MessageTask
+import com.android.net.module.util.TimerFileDescriptor.RunnableTask
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.tryTest
@@ -33,13 +38,21 @@
import kotlin.test.assertFalse
import kotlin.test.assertTrue
+private const val MSG_TEST = 1
+
@DevSdkIgnoreRunner.MonitorThreadLeak
@RunWith(DevSdkIgnoreRunner::class)
@SmallTest
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
class TimerFileDescriptorTest {
+ private class TestHandler(looper: Looper) : Handler(looper) {
+ override fun handleMessage(msg: Message) {
+ val cv = msg.obj as ConditionVariable
+ cv.open()
+ }
+ }
private val thread = HandlerThread(TimerFileDescriptorTest::class.simpleName).apply { start() }
- private val handler by lazy { Handler(thread.looper) }
+ private val handler by lazy { TestHandler(thread.looper) }
@After
fun tearDown() {
@@ -47,18 +60,33 @@
thread.join()
}
+ private fun assertDelayedTaskPost(
+ timerFd: TimerFileDescriptor,
+ task: ITask,
+ cv: ConditionVariable
+ ) {
+ val delayTime = 10L
+ val startTime1 = Instant.now()
+ handler.post { timerFd.setDelayedTask(task, delayTime) }
+ assertTrue(cv.block(100L /* timeoutMs*/))
+ assertTrue(Duration.between(startTime1, Instant.now()).toMillis() >= delayTime)
+ }
+
@Test
fun testSetDelayedTask() {
- val delayTime = 10L
val timerFd = TimerFileDescriptor(handler)
- val cv = ConditionVariable()
- val startTime = Instant.now()
tryTest {
- handler.post { timerFd.setDelayedTask({ cv.open() }, delayTime) }
- assertTrue(cv.block(100L /* timeoutMs*/))
- // Verify that the delay time has actually passed.
- val duration = Duration.between(startTime, Instant.now())
- assertTrue(duration.toMillis() >= delayTime)
+ // Verify the delayed task is executed with the self-implemented ITask
+ val cv1 = ConditionVariable()
+ assertDelayedTaskPost(timerFd, { cv1.open() }, cv1)
+
+ // Verify the delayed task is executed with the RunnableTask
+ val cv2 = ConditionVariable()
+ assertDelayedTaskPost(timerFd, RunnableTask{ cv2.open() }, cv2)
+
+ // Verify the delayed task is executed with the MessageTask
+ val cv3 = ConditionVariable()
+ assertDelayedTaskPost(timerFd, MessageTask(handler.obtainMessage(MSG_TEST, cv3)), cv3)
} cleanup {
visibleOnHandlerThread(handler) { timerFd.close() }
}