From b84bb3b4487c2ea19aec838cc9d3c4e45a79f2c9 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Thu, 14 Nov 2024 08:21:53 +0000 Subject: [PATCH] Add Abstract Class for RealtimeScheduler Because some APIs in RealtimeScheduler are higher than the min SDK version for the standalone MDNS build, an abstract class is required to allow the standalone MDNS build to pass. Bug: 366373064 Test: atest FrameworksNetTests NsdManagerTest m service-connectivity-mdns-standalone-build-test Change-Id: I0b3ac7b4f8dfceeb3dd81e6a5f368b5d57927c41 --- service-t/Android.bp | 9 ++- .../connectivity/mdns/DiscoveryExecutor.java | 21 ++++--- .../mdns/MdnsServiceTypeClient.java | 37 ++++++------ .../server/connectivity/mdns/Scheduler.java | 51 +++++++++++++++++ .../connectivity/mdns/SchedulerFactory.java | 38 +++++++++++++ .../mdns/internal/MdnsRealtimeScheduler.java | 57 +++++++++++++++++++ staticlibs/Android.bp | 4 -- .../mdns/MdnsServiceTypeClientTests.java | 26 ++++----- 8 files changed, 193 insertions(+), 50 deletions(-) create mode 100644 service-t/src/com/android/server/connectivity/mdns/Scheduler.java create mode 100644 service-t/src/com/android/server/connectivity/mdns/SchedulerFactory.java create mode 100644 service-t/src/com/android/server/connectivity/mdns/internal/MdnsRealtimeScheduler.java diff --git a/service-t/Android.bp b/service-t/Android.bp index ab38c7a22d..81378f5ead 100644 --- a/service-t/Android.bp +++ b/service-t/Android.bp @@ -109,13 +109,15 @@ java_library { ":service-mdns-droidstubs", ], exclude_srcs: [ + "src/com/android/server/connectivity/mdns/internal/MdnsRealtimeScheduler.java", "src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java", - "src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java", "src/com/android/server/connectivity/mdns/MdnsAdvertiser.java", "src/com/android/server/connectivity/mdns/MdnsAnnouncer.java", "src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java", "src/com/android/server/connectivity/mdns/MdnsProber.java", "src/com/android/server/connectivity/mdns/MdnsRecordRepository.java", + "src/com/android/server/connectivity/mdns/SchedulerFactory.java", + "src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java", ], static_libs: [ "net-utils-device-common-mdns-standalone-build-test", @@ -132,7 +134,10 @@ java_library { droidstubs { name: "service-mdns-droidstubs", - srcs: ["src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java"], + srcs: [ + "src/com/android/server/connectivity/mdns/SchedulerFactory.java", + "src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java", + ], libs: [ "net-utils-device-common-mdns-standalone-build-test", "service-connectivity-tiramisu-pre-jarjar", diff --git a/service-t/src/com/android/server/connectivity/mdns/DiscoveryExecutor.java b/service-t/src/com/android/server/connectivity/mdns/DiscoveryExecutor.java index 5b6ec9dfbb..99354f89ce 100644 --- a/service-t/src/com/android/server/connectivity/mdns/DiscoveryExecutor.java +++ b/service-t/src/com/android/server/connectivity/mdns/DiscoveryExecutor.java @@ -27,7 +27,6 @@ import android.util.Pair; import androidx.annotation.GuardedBy; import com.android.net.module.util.HandlerUtils; -import com.android.net.module.util.RealtimeScheduler; import java.util.ArrayList; import java.util.concurrent.Executor; @@ -52,7 +51,7 @@ public class DiscoveryExecutor implements Executor { @GuardedBy("mPendingTasks") @Nullable - RealtimeScheduler mRealtimeScheduler; + Scheduler mScheduler; @NonNull private final MdnsFeatureFlags mMdnsFeatureFlags; DiscoveryExecutor(@Nullable Looper defaultLooper, @NonNull MdnsFeatureFlags mdnsFeatureFlags) { @@ -102,7 +101,7 @@ public class DiscoveryExecutor implements Executor { /** Execute the given function after the specified amount of time elapses. */ public void executeDelayed(Runnable function, long delayMillis) { final Handler handler; - final RealtimeScheduler realtimeScheduler; + final Scheduler scheduler; synchronized (mPendingTasks) { if (this.mHandler == null) { mPendingTasks.add(Pair.create(function, delayMillis)); @@ -110,21 +109,21 @@ public class DiscoveryExecutor implements Executor { } else { handler = this.mHandler; if (mMdnsFeatureFlags.mIsAccurateDelayCallbackEnabled - && this.mRealtimeScheduler == null) { - this.mRealtimeScheduler = new RealtimeScheduler(mHandler); + && this.mScheduler == null) { + this.mScheduler = SchedulerFactory.createScheduler(mHandler); } - realtimeScheduler = this.mRealtimeScheduler; + scheduler = this.mScheduler; } } - if (realtimeScheduler != null) { + if (scheduler != null) { if (delayMillis == 0L) { handler.post(function); return; } if (HandlerUtils.isRunningOnHandlerThread(handler)) { - realtimeScheduler.postDelayed(function, delayMillis); + scheduler.postDelayed(function, delayMillis); } else { - handler.post(() -> realtimeScheduler.postDelayed(function, delayMillis)); + handler.post(() -> scheduler.postDelayed(function, delayMillis)); } } else { handler.postDelayed(function, delayMillis); @@ -137,8 +136,8 @@ public class DiscoveryExecutor implements Executor { this.mHandlerThread.quitSafely(); } synchronized (mPendingTasks) { - if (mRealtimeScheduler != null) { - mRealtimeScheduler.close(); + if (mScheduler != null) { + mScheduler.close(); } } } 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 56d4b9aff2..95f4fffa7a 100644 --- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java +++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java @@ -37,7 +37,6 @@ import androidx.annotation.VisibleForTesting; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.DnsUtils; -import com.android.net.module.util.RealtimeScheduler; import com.android.net.module.util.SharedLog; import com.android.server.connectivity.mdns.util.MdnsUtils; @@ -96,9 +95,9 @@ public class MdnsServiceTypeClient { private final boolean removeServiceAfterTtlExpires = MdnsConfigs.removeServiceAfterTtlExpires(); private final Clock clock; - // Use RealtimeScheduler for query scheduling, which allows for more accurate sending of + // Use MdnsRealtimeScheduler for query scheduling, which allows for more accurate sending of // queries. - @Nullable private final RealtimeScheduler realtimeScheduler; + @Nullable private final Scheduler scheduler; @Nullable private MdnsSearchOptions searchOptions; @@ -193,7 +192,7 @@ public class MdnsServiceTypeClient { sharedLog.log(String.format("Query sent with transactionId: %d. " + "Next run: sessionId: %d, in %d ms", sentResult.transactionId, args.sessionId, timeToNextTaskMs)); - if (realtimeScheduler != null) { + if (scheduler != null) { setDelayedTask(args, timeToNextTaskMs); } else { dependencies.sendMessageDelayed( @@ -264,11 +263,11 @@ public class MdnsServiceTypeClient { } /** - * @see RealtimeScheduler + * @see Scheduler */ @Nullable - public RealtimeScheduler createRealtimeScheduler(@NonNull Handler handler) { - return new RealtimeScheduler(handler); + public Scheduler createScheduler(@NonNull Handler handler) { + return SchedulerFactory.createScheduler(handler); } } @@ -317,8 +316,8 @@ public class MdnsServiceTypeClient { this.mdnsQueryScheduler = new MdnsQueryScheduler(); this.cacheKey = new MdnsServiceCache.CacheKey(serviceType, socketKey); this.featureFlags = featureFlags; - this.realtimeScheduler = featureFlags.isAccurateDelayCallbackEnabled() - ? dependencies.createRealtimeScheduler(handler) : null; + this.scheduler = featureFlags.isAccurateDelayCallbackEnabled() + ? dependencies.createScheduler(handler) : null; } /** @@ -328,8 +327,8 @@ public class MdnsServiceTypeClient { removeScheduledTask(); mdnsQueryScheduler.cancelScheduledRun(); serviceCache.unregisterServiceExpiredCallback(cacheKey); - if (realtimeScheduler != null) { - realtimeScheduler.close(); + if (scheduler != null) { + scheduler.close(); } } @@ -339,8 +338,8 @@ public class MdnsServiceTypeClient { } private void setDelayedTask(ScheduledQueryTaskArgs args, long timeToNextTaskMs) { - realtimeScheduler.removeDelayedMessage(EVENT_START_QUERYTASK); - realtimeScheduler.sendDelayedMessage( + scheduler.removeDelayedMessage(EVENT_START_QUERYTASK); + scheduler.sendDelayedMessage( handler.obtainMessage(EVENT_START_QUERYTASK, args), timeToNextTaskMs); } @@ -404,7 +403,7 @@ public class MdnsServiceTypeClient { final long timeToNextTaskMs = calculateTimeToNextTask(args, now); sharedLog.log(String.format("Schedule a query. Next run: sessionId: %d, in %d ms", args.sessionId, timeToNextTaskMs)); - if (realtimeScheduler != null) { + if (scheduler != null) { setDelayedTask(args, timeToNextTaskMs); } else { dependencies.sendMessageDelayed( @@ -451,8 +450,8 @@ public class MdnsServiceTypeClient { } private void removeScheduledTask() { - if (realtimeScheduler != null) { - realtimeScheduler.removeDelayedMessage(EVENT_START_QUERYTASK); + if (scheduler != null) { + scheduler.removeDelayedMessage(EVENT_START_QUERYTASK); } else { dependencies.removeMessages(handler, EVENT_START_QUERYTASK); } @@ -541,8 +540,8 @@ public class MdnsServiceTypeClient { } } } - final boolean hasScheduledTask = realtimeScheduler != null - ? realtimeScheduler.hasDelayedMessage(EVENT_START_QUERYTASK) + final boolean hasScheduledTask = scheduler != null + ? scheduler.hasDelayedMessage(EVENT_START_QUERYTASK) : dependencies.hasMessages(handler, EVENT_START_QUERYTASK); if (hasScheduledTask) { final long now = clock.elapsedRealtime(); @@ -556,7 +555,7 @@ public class MdnsServiceTypeClient { final long timeToNextTaskMs = calculateTimeToNextTask(args, now); sharedLog.log(String.format("Reschedule a query. Next run: sessionId: %d, in %d ms", args.sessionId, timeToNextTaskMs)); - if (realtimeScheduler != null) { + if (scheduler != null) { setDelayedTask(args, timeToNextTaskMs); } else { dependencies.sendMessageDelayed( diff --git a/service-t/src/com/android/server/connectivity/mdns/Scheduler.java b/service-t/src/com/android/server/connectivity/mdns/Scheduler.java new file mode 100644 index 0000000000..85a8e76f22 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/Scheduler.java @@ -0,0 +1,51 @@ +/* + * 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.server.connectivity.mdns; + +import android.os.Message; + +import androidx.annotation.NonNull; + +/** + * The interface for scheduler. + */ +public interface Scheduler { + /** + * Set a message to be sent after a specified delay. + */ + boolean sendDelayedMessage(@NonNull Message message, long delayMs); + + /** + * Remove a scheduled message. + */ + void removeDelayedMessage(int what); + + /** + * Check if there is a scheduled message. + */ + boolean hasDelayedMessage(int what); + + /** + * Set a runnable to be executed after a specified delay. + */ + boolean postDelayed(@NonNull Runnable runnable, long delayMs); + + /** + * Close this object. + */ + void close(); +} diff --git a/service-t/src/com/android/server/connectivity/mdns/SchedulerFactory.java b/service-t/src/com/android/server/connectivity/mdns/SchedulerFactory.java new file mode 100644 index 0000000000..1cc9a6b58b --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/SchedulerFactory.java @@ -0,0 +1,38 @@ +/* + * 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.server.connectivity.mdns; + +import android.annotation.NonNull; +import android.os.Handler; + +import com.android.server.connectivity.mdns.internal.MdnsRealtimeScheduler; + +/** + * The factory class for creating a scheduler. + */ +public class SchedulerFactory { + + /** + * Creates an realtime delay callback. + */ + public static Scheduler createScheduler(@NonNull Handler handler) { + return new MdnsRealtimeScheduler(handler); + } + + private SchedulerFactory() { + } +} diff --git a/service-t/src/com/android/server/connectivity/mdns/internal/MdnsRealtimeScheduler.java b/service-t/src/com/android/server/connectivity/mdns/internal/MdnsRealtimeScheduler.java new file mode 100644 index 0000000000..eff7085809 --- /dev/null +++ b/service-t/src/com/android/server/connectivity/mdns/internal/MdnsRealtimeScheduler.java @@ -0,0 +1,57 @@ +/* + * 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.server.connectivity.mdns.internal; + +import android.os.Handler; +import android.os.Message; + +import androidx.annotation.NonNull; + +import com.android.net.module.util.RealtimeScheduler; +import com.android.server.connectivity.mdns.Scheduler; + +/** + * The delay callback for delivering scheduled tasks accurately. + */ +public class MdnsRealtimeScheduler extends RealtimeScheduler implements + Scheduler { + private static final String TAG = MdnsRealtimeScheduler.class.getSimpleName(); + + public MdnsRealtimeScheduler(@NonNull Handler handler) { + super(handler); + } + + public boolean sendDelayedMessage(@NonNull Message message, long delayMs) { + return super.sendDelayedMessage(message, delayMs); + } + + public void removeDelayedMessage(int what) { + super.removeDelayedMessage(what); + } + + public boolean hasDelayedMessage(int what) { + return super.hasDelayedMessage(what); + } + + public boolean postDelayed(@NonNull Runnable runnable, long delayMs) { + return super.postDelayed(runnable, delayMs); + } + + public void close() { + super.close(); + } +} diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp index 8034e57e2a..0eab6e74d6 100644 --- a/staticlibs/Android.bp +++ b/staticlibs/Android.bp @@ -438,11 +438,7 @@ java_library { srcs: [ "device/com/android/net/module/util/FdEventsReader.java", "device/com/android/net/module/util/HandlerUtils.java", - "device/com/android/net/module/util/JniUtil.java", - "device/com/android/net/module/util/RealtimeScheduler.java", "device/com/android/net/module/util/SharedLog.java", - "device/com/android/net/module/util/ServiceConnectivityJni.java", - "device/com/android/net/module/util/TimerFdUtils.java", "framework/com/android/net/module/util/ByteUtils.java", "framework/com/android/net/module/util/CollectionUtils.java", "framework/com/android/net/module/util/DnsUtils.java", diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java index dad03e0631..b9c0d2f7ca 100644 --- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java +++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java @@ -59,7 +59,6 @@ import android.os.Message; import android.text.TextUtils; import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.RealtimeScheduler; import com.android.net.module.util.SharedLog; import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry; import com.android.server.connectivity.mdns.util.MdnsUtils; @@ -129,7 +128,7 @@ public class MdnsServiceTypeClientTests { @Mock private MdnsServiceTypeClient.Dependencies mockDeps; @Mock - private RealtimeScheduler mockRealtimeScheduler; + private Scheduler mockScheduler; @Captor private ArgumentCaptor serviceInfoCaptor; @@ -250,14 +249,14 @@ public class MdnsServiceTypeClientTests { doAnswer(inv -> { realHandler = (Handler) inv.getArguments()[0]; - return mockRealtimeScheduler; - }).when(mockDeps).createRealtimeScheduler(any(Handler.class)); + return mockScheduler; + }).when(mockDeps).createScheduler(any(Handler.class)); doAnswer(inv -> { message = (Message) inv.getArguments()[0]; latestDelayMs = (long) inv.getArguments()[1]; return null; - }).when(mockRealtimeScheduler).sendDelayedMessage(any(), anyLong()); + }).when(mockScheduler).sendDelayedMessage(any(), anyLong()); client = makeMdnsServiceTypeClient(featureFlags); } @@ -2137,7 +2136,7 @@ public class MdnsServiceTypeClientTests { .setNumOfQueriesBeforeBackoff(numOfQueriesBeforeBackoff) .build(); startSendAndReceive(mockListenerOne, searchOptions); - verify(mockRealtimeScheduler, times(1)).removeDelayedMessage(EVENT_START_QUERYTASK); + verify(mockScheduler, times(1)).removeDelayedMessage(EVENT_START_QUERYTASK); // Verify that the first query has been sent. verifyAndSendQuery(0 /* index */, 0 /* timeInMs */, true /* expectsUnicastResponse */, @@ -2159,13 +2158,13 @@ public class MdnsServiceTypeClientTests { // 0.8 * smallestRemainingTtl is larger than time to next run. long currentTime = TEST_TTL / 2 + TEST_ELAPSED_REALTIME; doReturn(currentTime).when(mockDecoderClock).elapsedRealtime(); - doReturn(true).when(mockRealtimeScheduler).hasDelayedMessage(EVENT_START_QUERYTASK); + doReturn(true).when(mockScheduler).hasDelayedMessage(EVENT_START_QUERYTASK); processResponse(createResponse( "service-instance-1", "192.0.2.123", 5353, SERVICE_TYPE_LABELS, Collections.emptyMap(), TEST_TTL), socketKey); // Verify that the message removal occurred. - verify(mockRealtimeScheduler, times(6)).removeDelayedMessage(EVENT_START_QUERYTASK); + verify(mockScheduler, times(6)).removeDelayedMessage(EVENT_START_QUERYTASK); assertNotNull(message); verifyAndSendQuery(3 /* index */, (long) (TEST_TTL / 2 * 0.8) /* timeInMs */, true /* expectsUnicastResponse */, true /* multipleSocketDiscovery */, @@ -2174,7 +2173,7 @@ public class MdnsServiceTypeClientTests { // Stop sending packets. stopSendAndReceive(mockListenerOne); - verify(mockRealtimeScheduler, times(8)).removeDelayedMessage(EVENT_START_QUERYTASK); + verify(mockScheduler, times(8)).removeDelayedMessage(EVENT_START_QUERYTASK); } @Test @@ -2184,12 +2183,12 @@ public class MdnsServiceTypeClientTests { // Start query startSendAndReceive(mockListenerOne, MdnsSearchOptions.newBuilder().build()); - verify(mockRealtimeScheduler, times(1)).removeDelayedMessage(EVENT_START_QUERYTASK); + verify(mockScheduler, times(1)).removeDelayedMessage(EVENT_START_QUERYTASK); // Stop query and verify the close() method has been called. stopSendAndReceive(mockListenerOne); - verify(mockRealtimeScheduler, times(2)).removeDelayedMessage(EVENT_START_QUERYTASK); - verify(mockRealtimeScheduler).close(); + verify(mockScheduler, times(2)).removeDelayedMessage(EVENT_START_QUERYTASK); + verify(mockScheduler).close(); } private static MdnsServiceInfo matchServiceName(String name) { @@ -2247,8 +2246,7 @@ public class MdnsServiceTypeClientTests { .sendMessage(any(Handler.class), any(Message.class)); // Verify the task has been scheduled. if (useAccurateDelayCallback) { - verify(mockRealtimeScheduler, times(scheduledCount)) - .sendDelayedMessage(any(), anyLong()); + verify(mockScheduler, times(scheduledCount)).sendDelayedMessage(any(), anyLong()); } else { verify(mockDeps, times(scheduledCount)) .sendMessageDelayed(any(Handler.class), any(Message.class), anyLong());