Loading core/java/android/util/NtpTrustedTime.java +69 −15 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,9 @@ import android.text.TextUtils; import com.android.internal.annotations.GuardedBy; 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.Objects; import java.util.function.Supplier; import java.util.function.Supplier; Loading Loading @@ -96,8 +99,8 @@ public class NtpTrustedTime implements TrustedTime { @Override @Override public String toString() { public String toString() { return "TimeResult{" return "TimeResult{" + "mTimeMillis=" + mTimeMillis + "mTimeMillis=" + Instant.ofEpochMilli(mTimeMillis) + ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis + ", mElapsedRealtimeMillis=" + Duration.ofMillis(mElapsedRealtimeMillis) + ", mCertaintyMillis=" + mCertaintyMillis + ", mCertaintyMillis=" + mCertaintyMillis + '}'; + '}'; } } Loading Loading @@ -131,6 +134,14 @@ public class NtpTrustedTime implements TrustedTime { } } }; }; /** 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 // Declared volatile and accessed outside of synchronized blocks to avoid blocking reads during // forceRefresh(). // forceRefresh(). private volatile TimeResult mTimeResult; private volatile TimeResult mTimeResult; Loading @@ -148,12 +159,23 @@ public class NtpTrustedTime implements TrustedTime { return sSingleton; 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) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean forceRefresh() { public boolean forceRefresh() { synchronized (this) { synchronized (this) { NtpConnectionInfo connectionInfo = getNtpConnectionInfo(); NtpConnectionInfo connectionInfo = getNtpConnectionInfo(); if (connectionInfo == null) { 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"); if (LOGD) Log.d(TAG, "forceRefresh: invalid server config"); return false; return false; } } Loading Loading @@ -290,6 +312,14 @@ public class NtpTrustedTime implements TrustedTime { int getTimeoutMillis() { int getTimeoutMillis() { return mTimeoutMillis; return mTimeoutMillis; } } @Override public String toString() { return "NtpConnectionInfo{" + "mServer='" + mServer + '\'' + ", mTimeoutMillis=" + mTimeoutMillis + '}'; } } } @GuardedBy("this") @GuardedBy("this") Loading @@ -297,17 +327,41 @@ public class NtpTrustedTime implements TrustedTime { final ContentResolver resolver = mContext.getContentResolver(); final ContentResolver resolver = mContext.getContentResolver(); final Resources res = mContext.getResources(); final Resources res = mContext.getResources(); final String defaultServer = res.getString( com.android.internal.R.string.config_ntpServer); final String hostname; final int defaultTimeoutMillis = res.getInteger( if (mHostnameForTests != null) { com.android.internal.R.integer.config_ntpTimeout); hostname = mHostnameForTests; } else { final String secureServer = Settings.Global.getString( String serverGlobalSetting = resolver, Settings.Global.NTP_SERVER); Settings.Global.getString(resolver, Settings.Global.NTP_SERVER); final int timeoutMillis = Settings.Global.getInt( if (serverGlobalSetting != null) { hostname = serverGlobalSetting; } else { hostname = res.getString(com.android.internal.R.string.config_ntpServer); } } 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); resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis); } return TextUtils.isEmpty(hostname) ? null : new NtpConnectionInfo(hostname, timeoutMillis); } final String server = secureServer != null ? secureServer : defaultServer; /** Prints debug information. */ return TextUtils.isEmpty(server) ? null : new NtpConnectionInfo(server, timeoutMillis); 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())); } } } } } } services/core/java/com/android/server/NetworkTimeUpdateService.java +23 −12 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server; package com.android.server; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.PendingIntent; import android.app.timedetector.NetworkTimeSuggestion; import android.app.timedetector.NetworkTimeSuggestion; Loading Loading @@ -45,12 +46,12 @@ import android.util.LocalLog; import android.util.Log; import android.util.Log; import android.util.NtpTrustedTime; import android.util.NtpTrustedTime; import android.util.NtpTrustedTime.TimeResult; import android.util.NtpTrustedTime.TimeResult; import android.util.TimeUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.DumpUtils; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.io.PrintWriter; 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 * Monitors the network time. If looking up the network time fails for some reason, it tries a few Loading Loading @@ -191,6 +192,19 @@ public class NetworkTimeUpdateService extends Binder { return success; 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) { private void onPollNetworkTime(int event) { // If we don't have any default network, don't bother. // If we don't have any default network, don't bother. if (mDefaultNetwork == null) return; if (mDefaultNetwork == null) return; Loading Loading @@ -349,17 +363,14 @@ public class NetworkTimeUpdateService extends Binder { @Override @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; pw.print("PollingIntervalMs: "); pw.println("mPollingIntervalMs=" + Duration.ofMillis(mPollingIntervalMs)); TimeUtils.formatDuration(mPollingIntervalMs, pw); pw.println("mPollingIntervalShorterMs=" + Duration.ofMillis(mPollingIntervalShorterMs)); pw.print("\nPollingIntervalShorterMs: "); pw.println("mTryAgainTimesMax=" + mTryAgainTimesMax); TimeUtils.formatDuration(mPollingIntervalShorterMs, pw); pw.println("mTryAgainCounter=" + mTryAgainCounter); pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax); pw.println(); pw.println("\nTryAgainCounter: " + mTryAgainCounter); pw.println("NtpTrustedTime:"); NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult(); mTime.dump(pw); pw.println("NTP cache result: " + ntpResult); pw.println(); if (ntpResult != null) { pw.println("NTP result age: " + ntpResult.getAgeMillis()); } pw.println("Local logs:"); pw.println("Local logs:"); mLocalLog.dump(fd, pw, args); mLocalLog.dump(fd, pw, args); pw.println(); pw.println(); Loading services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java +39 −0 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.os.ShellCommand; import android.os.ShellCommand; import java.io.PrintWriter; import java.io.PrintWriter; import java.time.Duration; import java.util.Objects; import java.util.Objects; /** Implements the shell command interface for {@link NetworkTimeUpdateService}. */ /** Implements the shell command interface for {@link NetworkTimeUpdateService}. */ Loading @@ -40,6 +41,13 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { */ */ private static final String SHELL_COMMAND_FORCE_REFRESH = "force_refresh"; 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 @NonNull private final NetworkTimeUpdateService mNetworkTimeUpdateService; private final NetworkTimeUpdateService mNetworkTimeUpdateService; Loading @@ -58,6 +66,8 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { return runClearTime(); return runClearTime(); case SHELL_COMMAND_FORCE_REFRESH: case SHELL_COMMAND_FORCE_REFRESH: return runForceRefresh(); return runForceRefresh(); case SHELL_COMMAND_SET_SERVER_CONFIG: return runSetServerConfig(); default: { default: { return handleDefaultCommands(cmd); return handleDefaultCommands(cmd); } } Loading @@ -75,6 +85,29 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { return 0; 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 @Override public void onHelp() { public void onHelp() { final PrintWriter pw = getOutPrintWriter(); final PrintWriter pw = getOutPrintWriter(); Loading @@ -85,6 +118,12 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { pw.printf(" Clears the latest time.\n"); pw.printf(" Clears the latest time.\n"); pw.printf(" %s\n", SHELL_COMMAND_FORCE_REFRESH); pw.printf(" %s\n", SHELL_COMMAND_FORCE_REFRESH); pw.printf(" Refreshes the latest time. Prints whether it was successful.\n"); 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(); pw.println(); } } } } Loading
core/java/android/util/NtpTrustedTime.java +69 −15 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,9 @@ import android.text.TextUtils; import com.android.internal.annotations.GuardedBy; 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.Objects; import java.util.function.Supplier; import java.util.function.Supplier; Loading Loading @@ -96,8 +99,8 @@ public class NtpTrustedTime implements TrustedTime { @Override @Override public String toString() { public String toString() { return "TimeResult{" return "TimeResult{" + "mTimeMillis=" + mTimeMillis + "mTimeMillis=" + Instant.ofEpochMilli(mTimeMillis) + ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis + ", mElapsedRealtimeMillis=" + Duration.ofMillis(mElapsedRealtimeMillis) + ", mCertaintyMillis=" + mCertaintyMillis + ", mCertaintyMillis=" + mCertaintyMillis + '}'; + '}'; } } Loading Loading @@ -131,6 +134,14 @@ public class NtpTrustedTime implements TrustedTime { } } }; }; /** 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 // Declared volatile and accessed outside of synchronized blocks to avoid blocking reads during // forceRefresh(). // forceRefresh(). private volatile TimeResult mTimeResult; private volatile TimeResult mTimeResult; Loading @@ -148,12 +159,23 @@ public class NtpTrustedTime implements TrustedTime { return sSingleton; 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) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean forceRefresh() { public boolean forceRefresh() { synchronized (this) { synchronized (this) { NtpConnectionInfo connectionInfo = getNtpConnectionInfo(); NtpConnectionInfo connectionInfo = getNtpConnectionInfo(); if (connectionInfo == null) { 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"); if (LOGD) Log.d(TAG, "forceRefresh: invalid server config"); return false; return false; } } Loading Loading @@ -290,6 +312,14 @@ public class NtpTrustedTime implements TrustedTime { int getTimeoutMillis() { int getTimeoutMillis() { return mTimeoutMillis; return mTimeoutMillis; } } @Override public String toString() { return "NtpConnectionInfo{" + "mServer='" + mServer + '\'' + ", mTimeoutMillis=" + mTimeoutMillis + '}'; } } } @GuardedBy("this") @GuardedBy("this") Loading @@ -297,17 +327,41 @@ public class NtpTrustedTime implements TrustedTime { final ContentResolver resolver = mContext.getContentResolver(); final ContentResolver resolver = mContext.getContentResolver(); final Resources res = mContext.getResources(); final Resources res = mContext.getResources(); final String defaultServer = res.getString( com.android.internal.R.string.config_ntpServer); final String hostname; final int defaultTimeoutMillis = res.getInteger( if (mHostnameForTests != null) { com.android.internal.R.integer.config_ntpTimeout); hostname = mHostnameForTests; } else { final String secureServer = Settings.Global.getString( String serverGlobalSetting = resolver, Settings.Global.NTP_SERVER); Settings.Global.getString(resolver, Settings.Global.NTP_SERVER); final int timeoutMillis = Settings.Global.getInt( if (serverGlobalSetting != null) { hostname = serverGlobalSetting; } else { hostname = res.getString(com.android.internal.R.string.config_ntpServer); } } 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); resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis); } return TextUtils.isEmpty(hostname) ? null : new NtpConnectionInfo(hostname, timeoutMillis); } final String server = secureServer != null ? secureServer : defaultServer; /** Prints debug information. */ return TextUtils.isEmpty(server) ? null : new NtpConnectionInfo(server, timeoutMillis); 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())); } } } } } }
services/core/java/com/android/server/NetworkTimeUpdateService.java +23 −12 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server; package com.android.server; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.PendingIntent; import android.app.timedetector.NetworkTimeSuggestion; import android.app.timedetector.NetworkTimeSuggestion; Loading Loading @@ -45,12 +46,12 @@ import android.util.LocalLog; import android.util.Log; import android.util.Log; import android.util.NtpTrustedTime; import android.util.NtpTrustedTime; import android.util.NtpTrustedTime.TimeResult; import android.util.NtpTrustedTime.TimeResult; import android.util.TimeUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.DumpUtils; import java.io.FileDescriptor; import java.io.FileDescriptor; import java.io.PrintWriter; 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 * Monitors the network time. If looking up the network time fails for some reason, it tries a few Loading Loading @@ -191,6 +192,19 @@ public class NetworkTimeUpdateService extends Binder { return success; 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) { private void onPollNetworkTime(int event) { // If we don't have any default network, don't bother. // If we don't have any default network, don't bother. if (mDefaultNetwork == null) return; if (mDefaultNetwork == null) return; Loading Loading @@ -349,17 +363,14 @@ public class NetworkTimeUpdateService extends Binder { @Override @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; pw.print("PollingIntervalMs: "); pw.println("mPollingIntervalMs=" + Duration.ofMillis(mPollingIntervalMs)); TimeUtils.formatDuration(mPollingIntervalMs, pw); pw.println("mPollingIntervalShorterMs=" + Duration.ofMillis(mPollingIntervalShorterMs)); pw.print("\nPollingIntervalShorterMs: "); pw.println("mTryAgainTimesMax=" + mTryAgainTimesMax); TimeUtils.formatDuration(mPollingIntervalShorterMs, pw); pw.println("mTryAgainCounter=" + mTryAgainCounter); pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax); pw.println(); pw.println("\nTryAgainCounter: " + mTryAgainCounter); pw.println("NtpTrustedTime:"); NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult(); mTime.dump(pw); pw.println("NTP cache result: " + ntpResult); pw.println(); if (ntpResult != null) { pw.println("NTP result age: " + ntpResult.getAgeMillis()); } pw.println("Local logs:"); pw.println("Local logs:"); mLocalLog.dump(fd, pw, args); mLocalLog.dump(fd, pw, args); pw.println(); pw.println(); Loading
services/core/java/com/android/server/NetworkTimeUpdateServiceShellCommand.java +39 −0 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.os.ShellCommand; import android.os.ShellCommand; import java.io.PrintWriter; import java.io.PrintWriter; import java.time.Duration; import java.util.Objects; import java.util.Objects; /** Implements the shell command interface for {@link NetworkTimeUpdateService}. */ /** Implements the shell command interface for {@link NetworkTimeUpdateService}. */ Loading @@ -40,6 +41,13 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { */ */ private static final String SHELL_COMMAND_FORCE_REFRESH = "force_refresh"; 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 @NonNull private final NetworkTimeUpdateService mNetworkTimeUpdateService; private final NetworkTimeUpdateService mNetworkTimeUpdateService; Loading @@ -58,6 +66,8 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { return runClearTime(); return runClearTime(); case SHELL_COMMAND_FORCE_REFRESH: case SHELL_COMMAND_FORCE_REFRESH: return runForceRefresh(); return runForceRefresh(); case SHELL_COMMAND_SET_SERVER_CONFIG: return runSetServerConfig(); default: { default: { return handleDefaultCommands(cmd); return handleDefaultCommands(cmd); } } Loading @@ -75,6 +85,29 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { return 0; 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 @Override public void onHelp() { public void onHelp() { final PrintWriter pw = getOutPrintWriter(); final PrintWriter pw = getOutPrintWriter(); Loading @@ -85,6 +118,12 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand { pw.printf(" Clears the latest time.\n"); pw.printf(" Clears the latest time.\n"); pw.printf(" %s\n", SHELL_COMMAND_FORCE_REFRESH); pw.printf(" %s\n", SHELL_COMMAND_FORCE_REFRESH); pw.printf(" Refreshes the latest time. Prints whether it was successful.\n"); 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(); pw.println(); } } } }