Merge "Make NTP config configurable from cmd"

This commit is contained in:
Neil Fuller
2022-03-04 11:41:14 +00:00
committed by Gerrit Code Review
3 changed files with 129 additions and 25 deletions

View File

@@ -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;
@@ -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
+ '}'; + '}';
} }
@@ -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;
@@ -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;
} }
@@ -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")
@@ -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 int defaultTimeoutMillis = res.getInteger(
com.android.internal.R.integer.config_ntpTimeout);
final String secureServer = Settings.Global.getString( final String hostname;
resolver, Settings.Global.NTP_SERVER); if (mHostnameForTests != null) {
final int timeoutMillis = Settings.Global.getInt( 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 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()));
}
}
} }
} }

View File

@@ -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;
@@ -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
@@ -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;
@@ -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();

View File

@@ -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}. */
@@ -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;
@@ -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);
} }
@@ -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();
@@ -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();
} }
} }