diff options
3 files changed, 154 insertions, 6 deletions
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java index 8604078b5ae5..40beab323576 100644 --- a/core/java/android/util/NtpTrustedTime.java +++ b/core/java/android/util/NtpTrustedTime.java @@ -265,6 +265,13 @@ public class NtpTrustedTime implements TrustedTime { return mTimeResult; } + /** Clears the last received NTP. Intended for use during tests. */ + public void clearCachedTimeResult() { + synchronized (this) { + mTimeResult = null; + } + } + private static class NtpConnectionInfo { @NonNull private final String mServer; diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index a0f239d43927..c73ce598c106 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -36,12 +36,15 @@ import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.PowerManager; +import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.SystemClock; import android.os.TimestampedValue; import android.provider.Settings; import android.util.LocalLog; import android.util.Log; import android.util.NtpTrustedTime; +import android.util.NtpTrustedTime.TimeResult; import android.util.TimeUtils; import com.android.internal.util.DumpUtils; @@ -152,6 +155,42 @@ public class NetworkTimeUpdateService extends Binder { }, new IntentFilter(ACTION_POLL)); } + /** + * Clears the cached NTP time. For use during tests to simulate when no NTP time is available. + * + * <p>This operation takes place in the calling thread rather than the service's handler thread. + */ + void clearTimeForTests() { + mContext.enforceCallingPermission( + android.Manifest.permission.SET_TIME, "clear latest network time"); + + mTime.clearCachedTimeResult(); + + mLocalLog.log("clearTimeForTests"); + } + + /** + * Forces the service to refresh the NTP time. + * + * <p>This operation takes place in the calling thread rather than the service's handler thread. + * This method does not affect currently scheduled refreshes. If the NTP request is successful + * it will make an (asynchronously handled) suggestion to the time detector. + */ + boolean forceRefreshForTests() { + mContext.enforceCallingPermission( + android.Manifest.permission.SET_TIME, "force network time refresh"); + + boolean success = mTime.forceRefresh(); + mLocalLog.log("forceRefreshForTests: success=" + success); + + if (success) { + makeNetworkTimeSuggestion(mTime.getCachedTimeResult(), + "Origin: NetworkTimeUpdateService: forceRefreshForTests"); + } + + return success; + } + private void onPollNetworkTime(int event) { // If we don't have any default network, don't bother. if (mDefaultNetwork == null) return; @@ -190,12 +229,8 @@ public class NetworkTimeUpdateService extends Binder { // Obtained fresh fix; schedule next normal update resetAlarm(mPollingIntervalMs); - // Suggest the time to the time detector. It may choose use it to set the system clock. - TimestampedValue<Long> timeSignal = new TimestampedValue<>( - cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis()); - NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal); - timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateService. event=" + event); - mTimeDetector.suggestNetworkTime(timeSuggestion); + makeNetworkTimeSuggestion(cachedNtpResult, + "Origin: NetworkTimeUpdateService. event=" + event); } else { // No fresh fix; schedule retry mTryAgainCounter++; @@ -214,6 +249,15 @@ public class NetworkTimeUpdateService extends Binder { } } + /** Suggests the time to the time detector. It may choose use it to set the system clock. */ + private void makeNetworkTimeSuggestion(TimeResult ntpResult, String debugInfo) { + TimestampedValue<Long> timeSignal = new TimestampedValue<>( + ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis()); + NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal); + timeSuggestion.addDebugInfo(debugInfo); + mTimeDetector.suggestNetworkTime(timeSuggestion); + } + /** * Cancel old alarm and starts a new one for the specified interval. * @@ -317,4 +361,11 @@ public class NetworkTimeUpdateService extends Binder { mLocalLog.dump(fd, pw, args); pw.println(); } + + @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { + new NetworkTimeUpdateServiceShellCommand(this).exec( + this, in, out, err, args, callback, resultReceiver); + } } diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java new file mode 100644 index 000000000000..dc93023d82c5 --- /dev/null +++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 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; + +import android.annotation.NonNull; +import android.os.ShellCommand; + +import java.io.PrintWriter; +import java.util.Objects; + +/** Implements the shell command interface for {@link NetworkTimeUpdateService}. */ +class NetworkTimeUpdateServiceShellCommand extends ShellCommand { + + /** + * The name of the service. + */ + 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. + */ + private static final String SHELL_COMMAND_FORCE_REFRESH = "force_refresh"; + + @NonNull + private final NetworkTimeUpdateService mNetworkTimeUpdateService; + + NetworkTimeUpdateServiceShellCommand(NetworkTimeUpdateService networkTimeUpdateService) { + mNetworkTimeUpdateService = Objects.requireNonNull(networkTimeUpdateService); + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + + switch (cmd) { + case SHELL_COMMAND_CLEAR_TIME: + return runClearTime(); + case SHELL_COMMAND_FORCE_REFRESH: + return runForceRefresh(); + default: { + return handleDefaultCommands(cmd); + } + } + } + + private int runClearTime() { + mNetworkTimeUpdateService.clearTimeForTests(); + return 0; + } + + private int runForceRefresh() { + boolean success = mNetworkTimeUpdateService.forceRefreshForTests(); + getOutPrintWriter().println(success); + return 0; + } + + @Override + public void onHelp() { + final PrintWriter pw = getOutPrintWriter(); + 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.println(); + } +} |