Merge "Make NTP config configurable from cmd" am: 271dfbe8df
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2007272
Change-Id: If16a743fc61890fd9e64856edc3bd8ccc9a4dd46
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 40beab3..aebc5e8 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -33,6 +33,9 @@
import com.android.internal.annotations.GuardedBy;
+import java.io.PrintWriter;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Objects;
import java.util.function.Supplier;
@@ -96,8 +99,8 @@
@Override
public String toString() {
return "TimeResult{"
- + "mTimeMillis=" + mTimeMillis
- + ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis
+ + "mTimeMillis=" + Instant.ofEpochMilli(mTimeMillis)
+ + ", mElapsedRealtimeMillis=" + Duration.ofMillis(mElapsedRealtimeMillis)
+ ", mCertaintyMillis=" + mCertaintyMillis
+ '}';
}
@@ -131,6 +134,14 @@
}
};
+ /** An in-memory config override for use during tests. */
+ @Nullable
+ private String mHostnameForTests;
+
+ /** An in-memory config override for use during tests. */
+ @Nullable
+ private Duration mTimeoutForTests;
+
// Declared volatile and accessed outside of synchronized blocks to avoid blocking reads during
// forceRefresh().
private volatile TimeResult mTimeResult;
@@ -148,12 +159,23 @@
return sSingleton;
}
+ /**
+ * Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
+ * test value, i.e. so the normal value will be used next time.
+ */
+ public void setServerConfigForTests(@Nullable String hostname, @Nullable Duration timeout) {
+ synchronized (this) {
+ mHostnameForTests = hostname;
+ mTimeoutForTests = timeout;
+ }
+ }
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean forceRefresh() {
synchronized (this) {
NtpConnectionInfo connectionInfo = getNtpConnectionInfo();
if (connectionInfo == null) {
- // missing server config, so no trusted time available
+ // missing server config, so no NTP time available
if (LOGD) Log.d(TAG, "forceRefresh: invalid server config");
return false;
}
@@ -290,6 +312,14 @@
int getTimeoutMillis() {
return mTimeoutMillis;
}
+
+ @Override
+ public String toString() {
+ return "NtpConnectionInfo{"
+ + "mServer='" + mServer + '\''
+ + ", mTimeoutMillis=" + mTimeoutMillis
+ + '}';
+ }
}
@GuardedBy("this")
@@ -297,17 +327,41 @@
final ContentResolver resolver = mContext.getContentResolver();
final Resources res = mContext.getResources();
- final String defaultServer = res.getString(
- com.android.internal.R.string.config_ntpServer);
- final int defaultTimeoutMillis = res.getInteger(
- com.android.internal.R.integer.config_ntpTimeout);
- final String secureServer = Settings.Global.getString(
- resolver, Settings.Global.NTP_SERVER);
- final int timeoutMillis = Settings.Global.getInt(
- resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis);
+ final String hostname;
+ if (mHostnameForTests != null) {
+ hostname = mHostnameForTests;
+ } else {
+ String serverGlobalSetting =
+ Settings.Global.getString(resolver, Settings.Global.NTP_SERVER);
+ if (serverGlobalSetting != null) {
+ hostname = serverGlobalSetting;
+ } else {
+ hostname = res.getString(com.android.internal.R.string.config_ntpServer);
+ }
+ }
- final String server = secureServer != null ? secureServer : defaultServer;
- return TextUtils.isEmpty(server) ? null : new NtpConnectionInfo(server, timeoutMillis);
+ final int timeoutMillis;
+ if (mTimeoutForTests != null) {
+ timeoutMillis = (int) mTimeoutForTests.toMillis();
+ } else {
+ int defaultTimeoutMillis =
+ res.getInteger(com.android.internal.R.integer.config_ntpTimeout);
+ timeoutMillis = Settings.Global.getInt(
+ resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis);
+ }
+ return TextUtils.isEmpty(hostname) ? null : new NtpConnectionInfo(hostname, timeoutMillis);
+ }
+
+ /** Prints debug information. */
+ public void dump(PrintWriter pw) {
+ synchronized (this) {
+ pw.println("getNtpConnectionInfo()=" + getNtpConnectionInfo());
+ pw.println("mTimeResult=" + mTimeResult);
+ if (mTimeResult != null) {
+ pw.println("mTimeResult.getAgeMillis()="
+ + Duration.ofMillis(mTimeResult.getAgeMillis()));
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 1e534b7..186ff62 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.timedetector.NetworkTimeSuggestion;
@@ -45,12 +46,12 @@
import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.NtpTrustedTime.TimeResult;
-import android.util.TimeUtils;
import com.android.internal.util.DumpUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.time.Duration;
/**
* Monitors the network time. If looking up the network time fails for some reason, it tries a few
@@ -191,6 +192,19 @@
return success;
}
+ /**
+ * Overrides the NTP server config for tests. Passing {@code null} to a parameter clears the
+ * test value, i.e. so the normal value will be used next time.
+ */
+ void setServerConfigForTests(@Nullable String hostname, @Nullable Duration timeout) {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.SET_TIME, "set NTP server config for tests");
+
+ mLocalLog.log("Setting server config for tests: hostname=" + hostname
+ + ", timeout=" + timeout);
+ mTime.setServerConfigForTests(hostname, timeout);
+ }
+
private void onPollNetworkTime(int event) {
// If we don't have any default network, don't bother.
if (mDefaultNetwork == null) return;
@@ -349,17 +363,14 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- pw.print("PollingIntervalMs: ");
- TimeUtils.formatDuration(mPollingIntervalMs, pw);
- pw.print("\nPollingIntervalShorterMs: ");
- TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
- pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
- pw.println("\nTryAgainCounter: " + mTryAgainCounter);
- NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult();
- pw.println("NTP cache result: " + ntpResult);
- if (ntpResult != null) {
- pw.println("NTP result age: " + ntpResult.getAgeMillis());
- }
+ pw.println("mPollingIntervalMs=" + Duration.ofMillis(mPollingIntervalMs));
+ pw.println("mPollingIntervalShorterMs=" + Duration.ofMillis(mPollingIntervalShorterMs));
+ pw.println("mTryAgainTimesMax=" + mTryAgainTimesMax);
+ pw.println("mTryAgainCounter=" + mTryAgainCounter);
+ pw.println();
+ pw.println("NtpTrustedTime:");
+ mTime.dump(pw);
+ pw.println();
pw.println("Local logs:");
mLocalLog.dump(fd, pw, args);
pw.println();
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
index dc93023..464af01 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java
@@ -20,6 +20,7 @@
import android.os.ShellCommand;
import java.io.PrintWriter;
+import java.time.Duration;
import java.util.Objects;
/** Implements the shell command interface for {@link NetworkTimeUpdateService}. */
@@ -40,6 +41,13 @@
*/
private static final String SHELL_COMMAND_FORCE_REFRESH = "force_refresh";
+ /**
+ * A shell command that sets the NTP server config for tests. Config is cleared on reboot.
+ */
+ private static final String SHELL_COMMAND_SET_SERVER_CONFIG = "set_server_config";
+ private static final String SET_SERVER_CONFIG_HOSTNAME_ARG = "--hostname";
+ private static final String SET_SERVER_CONFIG_TIMEOUT_ARG = "--timeout_millis";
+
@NonNull
private final NetworkTimeUpdateService mNetworkTimeUpdateService;
@@ -58,6 +66,8 @@
return runClearTime();
case SHELL_COMMAND_FORCE_REFRESH:
return runForceRefresh();
+ case SHELL_COMMAND_SET_SERVER_CONFIG:
+ return runSetServerConfig();
default: {
return handleDefaultCommands(cmd);
}
@@ -75,6 +85,29 @@
return 0;
}
+ private int runSetServerConfig() {
+ String hostname = null;
+ Duration timeout = null;
+ String opt;
+ while ((opt = getNextArg()) != null) {
+ switch (opt) {
+ case SET_SERVER_CONFIG_HOSTNAME_ARG: {
+ hostname = getNextArgRequired();
+ break;
+ }
+ case SET_SERVER_CONFIG_TIMEOUT_ARG: {
+ timeout = Duration.ofMillis(Integer.parseInt(getNextArgRequired()));
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("Unknown option: " + opt);
+ }
+ }
+ }
+ mNetworkTimeUpdateService.setServerConfigForTests(hostname, timeout);
+ return 0;
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -85,6 +118,12 @@
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);
+ pw.printf(" Sets the NTP server config for tests. The config is not persisted.\n");
+ pw.printf(" Options: [%s <hostname>] [%s <millis>]\n",
+ SET_SERVER_CONFIG_HOSTNAME_ARG, SET_SERVER_CONFIG_TIMEOUT_ARG);
+ pw.printf(" Each key/value is optional and must be specified to override the\n");
+ pw.printf(" normal value, not specifying a key causes it to reset to the original.\n");
pw.println();
}
}