From a6208228515e98ea0fb0642628e2a005f3bc9efb Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Tue, 31 Jan 2023 17:55:10 +0000 Subject: [PATCH] Make CTS tests ambivalent to server impl Implement shell command test support that will work regardless of which of the two location NetworkTimeHelper implementations is in use at the time. This is to prevent CTS breaking if OEMs or form factors switch the implementation to the new one during the next Android release cycle. New shell commands have been added temporarily to support the new SystemClockNetworkTimeTest and do the right thing depending on the implementation in use. This avoids the need for the tests to know which impl is in use. In a future release cycle, when the old impl is deleted these shell commands can be removed and the test changed as the new impl uses the time_detector and suitable commands (mostly) exist for other reasons. Bug: 222295093 Test: atest services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java Test: See associated CTS change Change-Id: Icca02ec263bb20bc02a0dd6dd6cc13342d9e4e7b --- .../app/timedetector/TimeDetector.java | 14 +++ core/java/android/util/NtpTrustedTime.java | 9 +- .../NetworkTimeUpdateService.java | 18 ---- .../NetworkTimeUpdateServiceShellCommand.java | 14 --- .../timedetector/TimeDetectorService.java | 96 +++++++++++++++---- .../TimeDetectorShellCommand.java | 40 +++++++- .../timedetector/TimeDetectorServiceTest.java | 59 ++++++------ 7 files changed, 159 insertions(+), 91 deletions(-) diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java index 50a7da1cede57..5ee10a50568d8 100644 --- a/core/java/android/app/timedetector/TimeDetector.java +++ b/core/java/android/app/timedetector/TimeDetector.java @@ -114,6 +114,20 @@ public interface TimeDetector { */ String SHELL_COMMAND_CONFIRM_TIME = "confirm_time"; + /** + * A shell command that clears the network time signal used by {@link + * SystemClock#currentNetworkTimeClock()}. + * @hide + */ + String SHELL_COMMAND_CLEAR_SYSTEM_CLOCK_NETWORK_TIME = "clear_system_clock_network_time"; + + /** + * A shell command that sets the network time signal used by {@link + * SystemClock#currentNetworkTimeClock()}. + * @hide + */ + String SHELL_COMMAND_SET_SYSTEM_CLOCK_NETWORK_TIME = "set_system_clock_network_time"; + /** * A shared utility method to create a {@link ManualTimeSuggestion}. * diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java index 98c0d7f4fbf17..5aa0f59024f8b 100644 --- a/core/java/android/util/NtpTrustedTime.java +++ b/core/java/android/util/NtpTrustedTime.java @@ -477,7 +477,14 @@ public abstract class NtpTrustedTime implements TrustedTime { return mTimeResult; } - /** Clears the last received NTP. Intended for use during tests. */ + /** Sets the last received NTP time. Intended for use during tests. */ + public void setCachedTimeResult(TimeResult timeResult) { + synchronized (this) { + mTimeResult = timeResult; + } + } + + /** Clears the last received NTP time. Intended for use during tests. */ public void clearCachedTimeResult() { synchronized (this) { mTimeResult = null; diff --git a/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java index 080929729fe35..a3ba7373b9216 100644 --- a/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateService.java @@ -180,24 +180,6 @@ public class NetworkTimeUpdateService extends Binder { } } - /** - * Clears the cached NTP time. For use during tests to simulate when no NTP time is available. - * - *

This operation takes place in the calling thread rather than the service's handler thread. - */ - @RequiresPermission(android.Manifest.permission.SET_TIME) - void clearTimeForTests() { - mContext.enforceCallingPermission( - android.Manifest.permission.SET_TIME, "clear latest network time"); - - final long token = Binder.clearCallingIdentity(); - try { - mNtpTrustedTime.clearCachedTimeResult(); - } finally { - Binder.restoreCallingIdentity(token); - } - } - /** * Forces the service to refresh the NTP time. * diff --git a/services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java index 410b50f8a88b2..b19ce59dc2f58 100644 --- a/services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java +++ b/services/core/java/com/android/server/timedetector/NetworkTimeUpdateServiceShellCommand.java @@ -36,11 +36,6 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { */ private static final String SHELL_COMMAND_SERVICE_NAME = "network_time_update_service"; - /** - * A shell command that clears the time signal received from the network. - */ - private static final String SHELL_COMMAND_CLEAR_TIME = "clear_time"; - /** * A shell command that forces the time signal to be refreshed from the network. */ @@ -73,8 +68,6 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { } switch (cmd) { - case SHELL_COMMAND_CLEAR_TIME: - return runClearTime(); case SHELL_COMMAND_FORCE_REFRESH: return runForceRefresh(); case SHELL_COMMAND_SET_SERVER_CONFIG: @@ -87,11 +80,6 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { } } - private int runClearTime() { - mNetworkTimeUpdateService.clearTimeForTests(); - return 0; - } - private int runForceRefresh() { boolean success = mNetworkTimeUpdateService.forceRefreshForTests(); getOutPrintWriter().println(success); @@ -147,8 +135,6 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { pw.printf("Network Time Update Service (%s) commands:\n", SHELL_COMMAND_SERVICE_NAME); pw.printf(" help\n"); pw.printf(" Print this help text.\n"); - pw.printf(" %s\n", SHELL_COMMAND_CLEAR_TIME); - pw.printf(" Clears the latest time.\n"); pw.printf(" %s\n", SHELL_COMMAND_FORCE_REFRESH); pw.printf(" Refreshes the latest time. Prints whether it was successful.\n"); pw.printf(" %s\n", SHELL_COMMAND_SET_SERVER_CONFIG); diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java index 0da967a3bc006..22f096b11f18a 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java @@ -37,6 +37,7 @@ import android.os.ParcelableException; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; +import android.os.SystemClock; import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.NtpTrustedTime; @@ -53,6 +54,7 @@ import com.android.server.timezonedetector.CurrentUserIdentityInjector; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.net.InetSocketAddress; import java.time.DateTimeException; import java.util.Objects; @@ -377,7 +379,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub * *

This operation takes place in the calling thread. */ - void clearNetworkTime() { + void clearLatestNetworkTime() { enforceSuggestNetworkTimePermission(); final long token = Binder.clearCallingIdentity(); @@ -390,12 +392,29 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub @Override public UnixEpochTime latestNetworkTime() { - NetworkTimeSuggestion suggestion = getLatestNetworkSuggestion(); - if (suggestion != null) { - return suggestion.getUnixEpochTime(); + NetworkTimeSuggestion latestNetworkTime; + // TODO(b/222295093): Remove this condition once we can be sure that all uses of + // NtpTrustedTime result in a suggestion being made to the time detector. + // mNtpTrustedTime can be removed once this happens. + if (TimeDetectorNetworkTimeHelper.isInUse()) { + // The new implementation. + latestNetworkTime = mTimeDetectorStrategy.getLatestNetworkSuggestion(); } else { + // The old implementation. + NtpTrustedTime.TimeResult ntpResult = mNtpTrustedTime.getCachedTimeResult(); + if (ntpResult != null) { + latestNetworkTime = new NetworkTimeSuggestion( + new UnixEpochTime( + ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis()), + ntpResult.getUncertaintyMillis()); + } else { + latestNetworkTime = null; + } + } + if (latestNetworkTime == null) { throw new ParcelableException(new DateTimeException("Missing network time fix")); } + return latestNetworkTime.getUnixEpochTime(); } /** @@ -403,23 +422,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub */ @Nullable NetworkTimeSuggestion getLatestNetworkSuggestion() { - // TODO(b/222295093): Return the latest network time from mTimeDetectorStrategy once we can - // be sure that all uses of NtpTrustedTime results in a suggestion being made to the time - // detector. mNtpTrustedTime can be removed once this happens. - if (TimeDetectorNetworkTimeHelper.isInUse()) { - // The new implementation. - return mTimeDetectorStrategy.getLatestNetworkSuggestion(); - } else { - // The old implementation. - NtpTrustedTime.TimeResult ntpResult = mNtpTrustedTime.getCachedTimeResult(); - if (ntpResult != null) { - UnixEpochTime unixEpochTime = new UnixEpochTime( - ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis()); - return new NetworkTimeSuggestion(unixEpochTime, ntpResult.getUncertaintyMillis()); - } else { - return null; - } - } + return mTimeDetectorStrategy.getLatestNetworkSuggestion(); } /** @@ -440,6 +443,57 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub mHandler.post(() -> mTimeDetectorStrategy.suggestExternalTime(timeSignal)); } + /** + * Sets the network time for testing {@link SystemClock#currentNetworkTimeClock()}. + * + *

This operation takes place in the calling thread. + */ + void setNetworkTimeForSystemClockForTests( + @NonNull UnixEpochTime unixEpochTime, int uncertaintyMillis) { + enforceSuggestNetworkTimePermission(); + + // TODO(b/222295093): Remove this condition once we can be sure that all uses of + // NtpTrustedTime result in a suggestion being made to the time detector. + // mNtpTrustedTime can be removed once this happens. + if (TimeDetectorNetworkTimeHelper.isInUse()) { + NetworkTimeSuggestion suggestion = + new NetworkTimeSuggestion(unixEpochTime, uncertaintyMillis); + suggestion.addDebugInfo("Injected for tests"); + mTimeDetectorStrategy.suggestNetworkTime(suggestion); + } else { + NtpTrustedTime.TimeResult timeResult = new NtpTrustedTime.TimeResult( + unixEpochTime.getUnixEpochTimeMillis(), + unixEpochTime.getElapsedRealtimeMillis(), + uncertaintyMillis, + InetSocketAddress.createUnresolved("time.set.for.tests", 123)); + mNtpTrustedTime.setCachedTimeResult(timeResult); + } + } + + /** + * Clears the network time for testing {@link SystemClock#currentNetworkTimeClock()}. + * + *

This operation takes place in the calling thread. + */ + void clearNetworkTimeForSystemClockForTests() { + enforceSuggestNetworkTimePermission(); + + final long token = Binder.clearCallingIdentity(); + try { + // TODO(b/222295093): Remove this condition once we can be sure that all uses of + // NtpTrustedTime result in a suggestion being made to the time detector. + // mNtpTrustedTime can be removed once this happens. + if (TimeDetectorNetworkTimeHelper.isInUse()) { + // Clear the latest network suggestion. Done in all c + mTimeDetectorStrategy.clearLatestNetworkSuggestion(); + } else { + mNtpTrustedTime.clearCachedTimeResult(); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + @Override protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @Nullable String[] args) { diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java b/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java index cce5709861689..fe0127fc11f28 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java @@ -16,12 +16,14 @@ package com.android.server.timedetector; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_CLEAR_NETWORK_TIME; +import static android.app.timedetector.TimeDetector.SHELL_COMMAND_CLEAR_SYSTEM_CLOCK_NETWORK_TIME; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_CONFIRM_TIME; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_GET_NETWORK_TIME; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_GET_TIME_STATE; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SERVICE_NAME; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED; +import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SET_SYSTEM_CLOCK_NETWORK_TIME; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SET_TIME_STATE; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_EXTERNAL_TIME; import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_GNSS_TIME; @@ -73,9 +75,9 @@ class TimeDetectorShellCommand extends ShellCommand { case SHELL_COMMAND_SUGGEST_NETWORK_TIME: return runSuggestNetworkTime(); case SHELL_COMMAND_GET_NETWORK_TIME: - return runGetNetworkTime(); + return runGetLatestNetworkTime(); case SHELL_COMMAND_CLEAR_NETWORK_TIME: - return runClearNetworkTime(); + return runClearLatestNetworkTime(); case SHELL_COMMAND_SUGGEST_GNSS_TIME: return runSuggestGnssTime(); case SHELL_COMMAND_SUGGEST_EXTERNAL_TIME: @@ -86,6 +88,10 @@ class TimeDetectorShellCommand extends ShellCommand { return runSetTimeState(); case SHELL_COMMAND_CONFIRM_TIME: return runConfirmTime(); + case SHELL_COMMAND_CLEAR_SYSTEM_CLOCK_NETWORK_TIME: + return runClearSystemClockNetworkTime(); + case SHELL_COMMAND_SET_SYSTEM_CLOCK_NETWORK_TIME: + return runSetSystemClockNetworkTime(); default: { return handleDefaultCommands(cmd); } @@ -128,15 +134,15 @@ class TimeDetectorShellCommand extends ShellCommand { mInterface::suggestNetworkTime); } - private int runGetNetworkTime() { + private int runGetLatestNetworkTime() { NetworkTimeSuggestion networkTimeSuggestion = mInterface.getLatestNetworkSuggestion(); final PrintWriter pw = getOutPrintWriter(); pw.println(networkTimeSuggestion); return 0; } - private int runClearNetworkTime() { - mInterface.clearNetworkTime(); + private int runClearLatestNetworkTime() { + mInterface.clearLatestNetworkTime(); return 0; } @@ -187,6 +193,20 @@ class TimeDetectorShellCommand extends ShellCommand { return 0; } + private int runClearSystemClockNetworkTime() { + mInterface.clearNetworkTimeForSystemClockForTests(); + return 0; + } + + private int runSetSystemClockNetworkTime() { + NetworkTimeSuggestion networkTimeSuggestion = + NetworkTimeSuggestion.parseCommandLineArg(this); + mInterface.setNetworkTimeForSystemClockForTests( + networkTimeSuggestion.getUnixEpochTime(), + networkTimeSuggestion.getUncertaintyMillis()); + return 0; + } + @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); @@ -218,6 +238,16 @@ class TimeDetectorShellCommand extends ShellCommand { pw.printf(" Prints the network time information held by the detector.\n"); pw.printf(" %s\n", SHELL_COMMAND_CLEAR_NETWORK_TIME); pw.printf(" Clears the network time information held by the detector.\n"); + // TODO(b/222295093) Remove these "system_clock" commands when + // SystemClock.currentNetworkTimeClock() is guaranteed to use the latest network + // suggestion. Then, commands above can be used instead. + pw.printf(" %s \n", + SHELL_COMMAND_SET_SYSTEM_CLOCK_NETWORK_TIME); + pw.printf(" Sets the network time information used for" + + " SystemClock.currentNetworkTimeClock().\n"); + pw.printf(" %s\n", SHELL_COMMAND_CLEAR_SYSTEM_CLOCK_NETWORK_TIME); + pw.printf(" Clears the network time information used for" + + " SystemClock.currentNetworkTimeClock().\n"); pw.println(); ManualTimeSuggestion.printCommandLineOpts(pw); pw.println(); diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java index 5a0867f8f584b..daa6823428366 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java @@ -386,70 +386,65 @@ public class TimeDetectorServiceTest { .when(mMockContext).enforceCallingPermission(anyString(), any()); assertThrows(SecurityException.class, - () -> mTimeDetectorService.clearNetworkTime()); + () -> mTimeDetectorService.clearLatestNetworkTime()); verify(mMockContext).enforceCallingPermission( eq(android.Manifest.permission.SET_TIME), anyString()); } @Test - public void testClearNetworkTime() throws Exception { + public void testClearLatestNetworkSuggestion() throws Exception { doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); - mTimeDetectorService.clearNetworkTime(); + mTimeDetectorService.clearLatestNetworkTime(); verify(mMockContext).enforceCallingPermission( eq(android.Manifest.permission.SET_TIME), anyString()); verify(mFakeTimeDetectorStrategySpy).clearLatestNetworkSuggestion(); } - @Test - public void testLatestNetworkTime() { - NtpTrustedTime.TimeResult latestNetworkTime = new NtpTrustedTime.TimeResult( - 1234L, 54321L, 999, InetSocketAddress.createUnresolved("test.timeserver", 123)); - when(mMockNtpTrustedTime.getCachedTimeResult()) - .thenReturn(latestNetworkTime); - UnixEpochTime expected = new UnixEpochTime( - latestNetworkTime.getElapsedRealtimeMillis(), latestNetworkTime.getTimeMillis()); - assertEquals(expected, mTimeDetectorService.latestNetworkTime()); - } - - @Test - public void testLatestNetworkTime_noTimeAvailable() { - when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null); - assertThrows(ParcelableException.class, () -> mTimeDetectorService.latestNetworkTime()); - } - @Test public void testGetLatestNetworkSuggestion() { - if (TimeDetectorNetworkTimeHelper.isInUse()) { - NetworkTimeSuggestion latestNetworkTime = createNetworkTimeSuggestion(); - mFakeTimeDetectorStrategySpy.setLatestNetworkTime(latestNetworkTime); + NetworkTimeSuggestion latestNetworkSuggestion = createNetworkTimeSuggestion(); + mFakeTimeDetectorStrategySpy.setLatestNetworkTime(latestNetworkSuggestion); - assertEquals(latestNetworkTime, mTimeDetectorService.getLatestNetworkSuggestion()); + assertEquals(latestNetworkSuggestion, mTimeDetectorService.getLatestNetworkSuggestion()); + } + + @Test + public void testGetLatestNetworkSuggestion_noTimeAvailable() { + mFakeTimeDetectorStrategySpy.setLatestNetworkTime(null); + + assertNull(mTimeDetectorService.getLatestNetworkSuggestion()); + } + + @Test + public void testLatestNetworkTime() { + if (TimeDetectorNetworkTimeHelper.isInUse()) { + NetworkTimeSuggestion latestNetworkSuggestion = createNetworkTimeSuggestion(); + mFakeTimeDetectorStrategySpy.setLatestNetworkTime(latestNetworkSuggestion); + + assertEquals(latestNetworkSuggestion.getUnixEpochTime(), + mTimeDetectorService.latestNetworkTime()); } else { NtpTrustedTime.TimeResult latestNetworkTime = new NtpTrustedTime.TimeResult( 1234L, 54321L, 999, InetSocketAddress.createUnresolved("test.timeserver", 123)); when(mMockNtpTrustedTime.getCachedTimeResult()) .thenReturn(latestNetworkTime); - UnixEpochTime expectedUnixEpochTime = new UnixEpochTime( + UnixEpochTime expected = new UnixEpochTime( latestNetworkTime.getElapsedRealtimeMillis(), latestNetworkTime.getTimeMillis()); - NetworkTimeSuggestion expected = new NetworkTimeSuggestion( - expectedUnixEpochTime, latestNetworkTime.getUncertaintyMillis()); - assertEquals(expected, mTimeDetectorService.getLatestNetworkSuggestion()); + assertEquals(expected, mTimeDetectorService.latestNetworkTime()); } } @Test - public void testGetLatestNetworkSuggestion_noTimeAvailable() { + public void testLatestNetworkTime_noTimeAvailable() { if (TimeDetectorNetworkTimeHelper.isInUse()) { mFakeTimeDetectorStrategySpy.setLatestNetworkTime(null); - - assertNull(mTimeDetectorService.getLatestNetworkSuggestion()); } else { when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null); - assertNull(mTimeDetectorService.getLatestNetworkSuggestion()); } + assertThrows(ParcelableException.class, () -> mTimeDetectorService.latestNetworkTime()); } @Test