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
This commit is contained in:
parent
0f4d1ab4d9
commit
b84bb3b448
8 changed files with 193 additions and 50 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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<MdnsServiceInfo> 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());
|
||||
|
|
|
|||
Loading…
Reference in a new issue