Loading core/java/android/provider/Settings.java +21 −6 Original line number Diff line number Diff line Loading @@ -12000,25 +12000,40 @@ public final class Settings { "nitz_network_disconnect_retention"; /** * The preferred NTP server. This setting overrides Android's static xml configuration when * present and valid. * SNTP client config: The preferred NTP server. This setting overrides the static * config.xml configuration when present and valid. * * <p>The legacy form is the NTP server name as a string. * <p>Newer code should use the form: ntp://{server name}[:port] (the standard NTP port, * 123, is used if not specified). * * <p>The settings value can consist of a pipe ("|") delimited list of server names or * ntp:// URIs. When present, all server name / ntp:// URIs must be valid or the entire * setting value will be ignored and Android's xml config will be used. * * <p>For example, the following examples are valid: * <ul> * <li>time.android.com</li> * <li>ntp://time.android.com</li> * <li>ntp://time.android.com:123</li> * <li>"time.android.com"</li> * <li>"ntp://time.android.com"</li> * <li>"ntp://time.android.com:123"</li> * <li>"time.android.com|time.other"</li> * <li>"ntp://time.android.com:123|ntp://time.other:123"</li> * <li>"time.android.com|ntp://time.other:123"</li> * </ul> * * @hide */ @Readable public static final String NTP_SERVER = "ntp_server"; /** Timeout in milliseconds to wait for NTP server. {@hide} */ /** * SNTP client config: Timeout to wait for an NTP server response. This setting overrides * the static config.xml configuration when present and valid. * * <p>The value is the timeout in milliseconds. It must be > 0. * * @hide */ @Readable public static final String NTP_TIMEOUT = "ntp_timeout"; Loading core/java/android/util/NtpTrustedTime.java +150 −51 Original line number Diff line number Diff line Loading @@ -40,6 +40,9 @@ import java.net.URI; import java.net.URISyntaxException; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.function.Supplier; Loading @@ -54,6 +57,9 @@ import java.util.function.Supplier; public abstract class NtpTrustedTime implements TrustedTime { private static final String URI_SCHEME_NTP = "ntp"; @VisibleForTesting public static final String NTP_SETTING_SERVER_NAME_DELIMITER = "|"; private static final String NTP_SETTING_SERVER_NAME_DELIMITER_REGEXP = "\\|"; /** * NTP server configuration. Loading @@ -62,21 +68,36 @@ public abstract class NtpTrustedTime implements TrustedTime { */ public static final class NtpConfig { @NonNull private final URI mServerUri; @NonNull private final List<URI> mServerUris; @NonNull private final Duration mTimeout; /** * Creates an instance. If the arguments are invalid then an {@link * IllegalArgumentException} will be thrown. See {@link #parseNtpUriStrict(String)} and * {@link #parseNtpServerSetting(String)} to create valid URIs. * Creates an instance with the supplied properties. There must be at least one NTP server * URI and the timeout must be non-zero / non-negative. * * <p>If the arguments are invalid then an {@link IllegalArgumentException} will be thrown. * See {@link #parseNtpUriStrict(String)} and {@link #parseNtpServerSetting(String)} to * create valid URIs. */ public NtpConfig(@NonNull URI serverUri, @NonNull Duration timeout) public NtpConfig(@NonNull List<URI> serverUris, @NonNull Duration timeout) throws IllegalArgumentException { Objects.requireNonNull(serverUris); if (serverUris.isEmpty()) { throw new IllegalArgumentException("Server URIs is empty"); } List<URI> validatedServerUris = new ArrayList<>(); for (URI serverUri : serverUris) { try { mServerUri = validateNtpServerUri(Objects.requireNonNull(serverUri)); URI validatedServerUri = validateNtpServerUri( Objects.requireNonNull(serverUri)); validatedServerUris.add(validatedServerUri); } catch (URISyntaxException e) { throw new IllegalArgumentException("Bad URI", e); throw new IllegalArgumentException("Bad server URI", e); } } mServerUris = Collections.unmodifiableList(validatedServerUris); if (timeout.isNegative() || timeout.isZero()) { throw new IllegalArgumentException("timeout < 0"); Loading @@ -84,9 +105,10 @@ public abstract class NtpTrustedTime implements TrustedTime { mTimeout = timeout; } /** Returns a non-empty, immutable list of NTP server URIs. */ @NonNull public URI getServerUri() { return mServerUri; public List<URI> getServerUris() { return mServerUris; } @NonNull Loading @@ -97,7 +119,7 @@ public abstract class NtpTrustedTime implements TrustedTime { @Override public String toString() { return "NtpConnectionInfo{" + "mServerUri=" + mServerUri + "mServerUris=" + mServerUris + ", mTimeout=" + mTimeout + '}'; } Loading Loading @@ -199,6 +221,10 @@ public abstract class NtpTrustedTime implements TrustedTime { @Nullable private NtpConfig mNtpConfigForTests; @GuardedBy("this") @Nullable private URI mLastSuccessfulNtpServerUri; // Declared volatile and accessed outside synchronized blocks to avoid blocking reads during // forceRefresh(). private volatile TimeResult mTimeResult; Loading Loading @@ -245,13 +271,59 @@ public abstract class NtpTrustedTime implements TrustedTime { Log.d(TAG, "forceRefresh: NTP request network=" + network + " ntpConfig=" + ntpConfig); } TimeResult timeResult = queryNtpServer(network, ntpConfig.getServerUri(), ntpConfig.getTimeout()); List<URI> unorderedServerUris = ntpConfig.getServerUris(); // Android supports multiple NTP server URIs for situations where servers might be // unreachable for some devices due to network topology, e.g. we understand that devices // travelling to China often have difficulty accessing "time.android.com". Android // partners may want to configure alternative URIs for devices sold globally, or those // that are likely to travel to part of the world without access to the full internet. // // The server URI list is expected to contain one element in the general case, with two // or three as the anticipated maximum. The list is never empty. Server URIs are // considered to be in a rough priority order of servers to try initially (no // randomization), but besides that there is assumed to be no preference. // // The server selection algorithm below tries to stick with a successfully accessed NTP // server's URI where possible: // // The algorithm based on the assumption that a cluster of NTP servers sharing the same // host name, particularly commercially run ones, are likely to agree more closely on // the time than servers from different URIs, so it's best to be sticky. Switching // between URIs could result in flip-flopping between reference clocks or involve // talking to server clusters with different approaches to leap second handling. // // Stickiness may also be useful if some server URIs early in the list are permanently // black-holing requests, or if the responses are not routed back. In those cases it's // best not to try those URIs more than we have to, as might happen if the algorithm // always started at the beginning of the list. // // Generally, we have to assume that any of the configured servers are going to be "good // enough" as an external reference clock when reachable, so the stickiness is a very // lightly applied bias. There's no tracking of failure rates or back-off on a per-URI // basis; higher level code is expected to handle rate limiting of NTP requests in the // event of failure to contact any server. List<URI> orderedServerUris = new ArrayList<>(); for (URI serverUri : unorderedServerUris) { if (serverUri.equals(mLastSuccessfulNtpServerUri)) { orderedServerUris.add(0, serverUri); } else { orderedServerUris.add(serverUri); } } for (URI serverUri : orderedServerUris) { TimeResult timeResult = queryNtpServer(network, serverUri, ntpConfig.getTimeout()); // Only overwrite previous state if the request was successful. if (timeResult != null) { // Keep any previous time result. mLastSuccessfulNtpServerUri = serverUri; mTimeResult = timeResult; return true; } } return timeResult != null; return false; } } Loading Loading @@ -388,7 +460,9 @@ public abstract class NtpTrustedTime implements TrustedTime { * <p>NTP server config URIs are in the form "ntp://{hostname}[:port]". This is not a registered * IANA URI scheme. */ public static URI parseNtpUriStrict(String ntpServerUriString) throws URISyntaxException { @NonNull public static URI parseNtpUriStrict(@NonNull String ntpServerUriString) throws URISyntaxException { // java.net.URI is used in preference to android.net.Uri, since android.net.Uri is very // forgiving of obvious errors. URI catches issues sooner. URI unvalidatedUri = new URI(ntpServerUriString); Loading @@ -396,50 +470,68 @@ public abstract class NtpTrustedTime implements TrustedTime { } /** * Parses a setting string and returns a URI that will be accepted by {@link NtpConfig}, or * {@code null} if the string does not produce a URI considered valid. * Parses a setting string and returns a list of URIs that will be accepted by {@link * NtpConfig}, or {@code null} if the string is invalid. * * <p>The setting string is expected to be one or more server values separated by a pipe ("|") * character. * * <p>NTP server config URIs are in the form "ntp://{hostname}[:port]". This is not a registered * IANA URI scheme. * * <p>Unlike {@link #parseNtpUriStrict(String)} this method will not throw an exception. It * checks for a leading "ntp:" and will call through to {@link #parseNtpUriStrict(String)} to * attempt to parse it, returning {@code null} if it fails. To support legacy settings values, * it will also accept a string that only consists of a server name, which will be coerced into * a URI in the form "ntp://{server name}". * checks each value for a leading "ntp:" and will call through to {@link * #parseNtpUriStrict(String)} to attempt to parse it, returning {@code null} if it fails. * To support legacy settings values, it will also accept string values that only consists of a * server name, which will be coerced into a URI in the form "ntp://{server name}". */ @VisibleForTesting public static URI parseNtpServerSetting(String ntpServerSetting) { @Nullable public static List<URI> parseNtpServerSetting(@Nullable String ntpServerSetting) { if (TextUtils.isEmpty(ntpServerSetting)) { return null; } else if (ntpServerSetting.startsWith(URI_SCHEME_NTP + ":")) { } else { String[] values = ntpServerSetting.split(NTP_SETTING_SERVER_NAME_DELIMITER_REGEXP); if (values.length == 0) { return null; } List<URI> uris = new ArrayList<>(); for (String value : values) { if (value.startsWith(URI_SCHEME_NTP + ":")) { try { return parseNtpUriStrict(ntpServerSetting); uris.add(parseNtpUriStrict(value)); } catch (URISyntaxException e) { Log.w(TAG, "Rejected NTP uri setting=" + ntpServerSetting, e); return null; } } else { // This is the legacy settings path. Assumes that the string is just a host name and // creates a URI in the form ntp://<host name> // This is the legacy settings path. Assumes that the string is just a host name // and creates a URI in the form ntp://<host name> try { URI uri = new URI(URI_SCHEME_NTP, /*host=*/ntpServerSetting, URI uri = new URI(URI_SCHEME_NTP, /*host=*/value, /*path=*/null, /*fragment=*/null); // Paranoia: validate just in case the host name somehow results in a bad URI. return validateNtpServerUri(uri); // Paranoia: validate just in case the host name somehow results in a bad // URI. URI validatedUri = validateNtpServerUri(uri); uris.add(validatedUri); } catch (URISyntaxException e) { Log.w(TAG, "Rejected NTP legacy setting=" + ntpServerSetting, e); return null; } } } return uris; } } /** * Checks that the supplied URI can be used to identify an NTP server. * This method currently ignores Uri components that are not used, only checking the parts that * must be present. Returns the supplied {@code uri} if validation is successful. */ private static URI validateNtpServerUri(URI uri) throws URISyntaxException { @NonNull private static URI validateNtpServerUri(@NonNull URI uri) throws URISyntaxException { if (!uri.isAbsolute()) { throw new URISyntaxException(uri.toString(), "Relative URI not supported"); } Loading @@ -457,6 +549,8 @@ public abstract class NtpTrustedTime implements TrustedTime { public void dump(PrintWriter pw) { synchronized (this) { pw.println("getNtpConfig()=" + getNtpConfig()); pw.println("mNtpConfigForTests=" + mNtpConfigForTests); pw.println("mLastSuccessfulNtpServerUri=" + mLastSuccessfulNtpServerUri); pw.println("mTimeResult=" + mTimeResult); if (mTimeResult != null) { pw.println("mTimeResult.getAgeMillis()=" Loading Loading @@ -508,17 +602,22 @@ public abstract class NtpTrustedTime implements TrustedTime { // The Settings value has priority over static config. Check settings first. final String serverGlobalSetting = Settings.Global.getString(resolver, Settings.Global.NTP_SERVER); final URI settingsServerInfo = parseNtpServerSetting(serverGlobalSetting); final List<URI> settingsServerUris = parseNtpServerSetting(serverGlobalSetting); URI ntpServerUri; if (settingsServerInfo != null) { ntpServerUri = settingsServerInfo; List<URI> ntpServerUris; if (settingsServerUris != null) { ntpServerUris = settingsServerUris; } else { String configValue = res.getString(com.android.internal.R.string.config_ntpServer); String[] configValues = res.getStringArray(com.android.internal.R.array.config_ntpServers); try { ntpServerUri = parseNtpUriStrict(configValue); List<URI> configServerUris = new ArrayList<>(); for (String configValue : configValues) { configServerUris.add(parseNtpUriStrict(configValue)); } ntpServerUris = configServerUris; } catch (URISyntaxException e) { ntpServerUri = null; ntpServerUris = null; } } Loading @@ -526,7 +625,7 @@ public abstract class NtpTrustedTime implements TrustedTime { res.getInteger(com.android.internal.R.integer.config_ntpTimeout); final Duration timeout = Duration.ofMillis(Settings.Global.getInt( resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis)); return ntpServerUri == null ? null : new NtpConfig(ntpServerUri, timeout); return ntpServerUris == null ? null : new NtpConfig(ntpServerUris, timeout); } @Override Loading core/res/res/values/config.xml +15 −9 Original line number Diff line number Diff line Loading @@ -2308,19 +2308,25 @@ it should be disabled in that locale's resources. --> <bool name="config_actionMenuItemAllCaps">true</bool> <!-- Remote server that can provide NTP responses. Values must be in the form: "ntp://<host>[:port]" <!-- SNTP client config: NTP servers to use to obtain an accurate time. Items must be in the form: "ntp://<host>[:port]" This is not a registered IANA URI scheme. --> <string translatable="false" name="config_ntpServer">ntp://time.android.com</string> <!-- Normal polling frequency in milliseconds --> <string-array translatable="false" name="config_ntpServers"> <item>ntp://time.android.com</item> </string-array> <!-- SNTP client config: Timeout to wait for an NTP server response in milliseconds. --> <integer name="config_ntpTimeout">5000</integer> <!-- Automatic "network" time detection config: Normal network time polling frequency in milliseconds. --> <integer name="config_ntpPollingInterval">64800000</integer> <!-- Try-again polling interval in milliseconds, in case the network request failed --> <!-- Automatic "network" time detection config: Try-again network time polling interval in milliseconds, in case the network request failed --> <integer name="config_ntpPollingIntervalShorter">60000</integer> <!-- Number of times to try again with the shorter interval, before backing off until the normal polling interval. A value < 0 indicates infinite. --> <!-- Automatic "network" time detection config: Number of times to try network time polling with the shorter interval, before backing off until the normal polling interval. A value < 0 indicates infinite. --> <integer name="config_ntpRetry">3</integer> <!-- Timeout to wait for NTP server response in milliseconds. --> <integer name="config_ntpTimeout">5000</integer> <!-- Default network policy warning threshold, in megabytes. --> <integer name="config_networkPolicyDefaultWarning">2048</integer> Loading core/res/res/values/symbols.xml +1 −1 Original line number Diff line number Diff line Loading @@ -697,7 +697,7 @@ <java-symbol type="string" name="config_forceVoiceInteractionServicePackage" /> <java-symbol type="string" name="config_mms_user_agent" /> <java-symbol type="string" name="config_mms_user_agent_profile_url" /> <java-symbol type="string" name="config_ntpServer" /> <java-symbol type="array" name="config_ntpServers" /> <java-symbol type="string" name="config_useragentprofile_url" /> <java-symbol type="string" name="config_appsNotReportingCrashes" /> <java-symbol type="string" name="contentServiceSync" /> Loading core/tests/coretests/src/android/util/NtpTrustedTimeTest.java +379 −97 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/provider/Settings.java +21 −6 Original line number Diff line number Diff line Loading @@ -12000,25 +12000,40 @@ public final class Settings { "nitz_network_disconnect_retention"; /** * The preferred NTP server. This setting overrides Android's static xml configuration when * present and valid. * SNTP client config: The preferred NTP server. This setting overrides the static * config.xml configuration when present and valid. * * <p>The legacy form is the NTP server name as a string. * <p>Newer code should use the form: ntp://{server name}[:port] (the standard NTP port, * 123, is used if not specified). * * <p>The settings value can consist of a pipe ("|") delimited list of server names or * ntp:// URIs. When present, all server name / ntp:// URIs must be valid or the entire * setting value will be ignored and Android's xml config will be used. * * <p>For example, the following examples are valid: * <ul> * <li>time.android.com</li> * <li>ntp://time.android.com</li> * <li>ntp://time.android.com:123</li> * <li>"time.android.com"</li> * <li>"ntp://time.android.com"</li> * <li>"ntp://time.android.com:123"</li> * <li>"time.android.com|time.other"</li> * <li>"ntp://time.android.com:123|ntp://time.other:123"</li> * <li>"time.android.com|ntp://time.other:123"</li> * </ul> * * @hide */ @Readable public static final String NTP_SERVER = "ntp_server"; /** Timeout in milliseconds to wait for NTP server. {@hide} */ /** * SNTP client config: Timeout to wait for an NTP server response. This setting overrides * the static config.xml configuration when present and valid. * * <p>The value is the timeout in milliseconds. It must be > 0. * * @hide */ @Readable public static final String NTP_TIMEOUT = "ntp_timeout"; Loading
core/java/android/util/NtpTrustedTime.java +150 −51 Original line number Diff line number Diff line Loading @@ -40,6 +40,9 @@ import java.net.URI; import java.net.URISyntaxException; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.function.Supplier; Loading @@ -54,6 +57,9 @@ import java.util.function.Supplier; public abstract class NtpTrustedTime implements TrustedTime { private static final String URI_SCHEME_NTP = "ntp"; @VisibleForTesting public static final String NTP_SETTING_SERVER_NAME_DELIMITER = "|"; private static final String NTP_SETTING_SERVER_NAME_DELIMITER_REGEXP = "\\|"; /** * NTP server configuration. Loading @@ -62,21 +68,36 @@ public abstract class NtpTrustedTime implements TrustedTime { */ public static final class NtpConfig { @NonNull private final URI mServerUri; @NonNull private final List<URI> mServerUris; @NonNull private final Duration mTimeout; /** * Creates an instance. If the arguments are invalid then an {@link * IllegalArgumentException} will be thrown. See {@link #parseNtpUriStrict(String)} and * {@link #parseNtpServerSetting(String)} to create valid URIs. * Creates an instance with the supplied properties. There must be at least one NTP server * URI and the timeout must be non-zero / non-negative. * * <p>If the arguments are invalid then an {@link IllegalArgumentException} will be thrown. * See {@link #parseNtpUriStrict(String)} and {@link #parseNtpServerSetting(String)} to * create valid URIs. */ public NtpConfig(@NonNull URI serverUri, @NonNull Duration timeout) public NtpConfig(@NonNull List<URI> serverUris, @NonNull Duration timeout) throws IllegalArgumentException { Objects.requireNonNull(serverUris); if (serverUris.isEmpty()) { throw new IllegalArgumentException("Server URIs is empty"); } List<URI> validatedServerUris = new ArrayList<>(); for (URI serverUri : serverUris) { try { mServerUri = validateNtpServerUri(Objects.requireNonNull(serverUri)); URI validatedServerUri = validateNtpServerUri( Objects.requireNonNull(serverUri)); validatedServerUris.add(validatedServerUri); } catch (URISyntaxException e) { throw new IllegalArgumentException("Bad URI", e); throw new IllegalArgumentException("Bad server URI", e); } } mServerUris = Collections.unmodifiableList(validatedServerUris); if (timeout.isNegative() || timeout.isZero()) { throw new IllegalArgumentException("timeout < 0"); Loading @@ -84,9 +105,10 @@ public abstract class NtpTrustedTime implements TrustedTime { mTimeout = timeout; } /** Returns a non-empty, immutable list of NTP server URIs. */ @NonNull public URI getServerUri() { return mServerUri; public List<URI> getServerUris() { return mServerUris; } @NonNull Loading @@ -97,7 +119,7 @@ public abstract class NtpTrustedTime implements TrustedTime { @Override public String toString() { return "NtpConnectionInfo{" + "mServerUri=" + mServerUri + "mServerUris=" + mServerUris + ", mTimeout=" + mTimeout + '}'; } Loading Loading @@ -199,6 +221,10 @@ public abstract class NtpTrustedTime implements TrustedTime { @Nullable private NtpConfig mNtpConfigForTests; @GuardedBy("this") @Nullable private URI mLastSuccessfulNtpServerUri; // Declared volatile and accessed outside synchronized blocks to avoid blocking reads during // forceRefresh(). private volatile TimeResult mTimeResult; Loading Loading @@ -245,13 +271,59 @@ public abstract class NtpTrustedTime implements TrustedTime { Log.d(TAG, "forceRefresh: NTP request network=" + network + " ntpConfig=" + ntpConfig); } TimeResult timeResult = queryNtpServer(network, ntpConfig.getServerUri(), ntpConfig.getTimeout()); List<URI> unorderedServerUris = ntpConfig.getServerUris(); // Android supports multiple NTP server URIs for situations where servers might be // unreachable for some devices due to network topology, e.g. we understand that devices // travelling to China often have difficulty accessing "time.android.com". Android // partners may want to configure alternative URIs for devices sold globally, or those // that are likely to travel to part of the world without access to the full internet. // // The server URI list is expected to contain one element in the general case, with two // or three as the anticipated maximum. The list is never empty. Server URIs are // considered to be in a rough priority order of servers to try initially (no // randomization), but besides that there is assumed to be no preference. // // The server selection algorithm below tries to stick with a successfully accessed NTP // server's URI where possible: // // The algorithm based on the assumption that a cluster of NTP servers sharing the same // host name, particularly commercially run ones, are likely to agree more closely on // the time than servers from different URIs, so it's best to be sticky. Switching // between URIs could result in flip-flopping between reference clocks or involve // talking to server clusters with different approaches to leap second handling. // // Stickiness may also be useful if some server URIs early in the list are permanently // black-holing requests, or if the responses are not routed back. In those cases it's // best not to try those URIs more than we have to, as might happen if the algorithm // always started at the beginning of the list. // // Generally, we have to assume that any of the configured servers are going to be "good // enough" as an external reference clock when reachable, so the stickiness is a very // lightly applied bias. There's no tracking of failure rates or back-off on a per-URI // basis; higher level code is expected to handle rate limiting of NTP requests in the // event of failure to contact any server. List<URI> orderedServerUris = new ArrayList<>(); for (URI serverUri : unorderedServerUris) { if (serverUri.equals(mLastSuccessfulNtpServerUri)) { orderedServerUris.add(0, serverUri); } else { orderedServerUris.add(serverUri); } } for (URI serverUri : orderedServerUris) { TimeResult timeResult = queryNtpServer(network, serverUri, ntpConfig.getTimeout()); // Only overwrite previous state if the request was successful. if (timeResult != null) { // Keep any previous time result. mLastSuccessfulNtpServerUri = serverUri; mTimeResult = timeResult; return true; } } return timeResult != null; return false; } } Loading Loading @@ -388,7 +460,9 @@ public abstract class NtpTrustedTime implements TrustedTime { * <p>NTP server config URIs are in the form "ntp://{hostname}[:port]". This is not a registered * IANA URI scheme. */ public static URI parseNtpUriStrict(String ntpServerUriString) throws URISyntaxException { @NonNull public static URI parseNtpUriStrict(@NonNull String ntpServerUriString) throws URISyntaxException { // java.net.URI is used in preference to android.net.Uri, since android.net.Uri is very // forgiving of obvious errors. URI catches issues sooner. URI unvalidatedUri = new URI(ntpServerUriString); Loading @@ -396,50 +470,68 @@ public abstract class NtpTrustedTime implements TrustedTime { } /** * Parses a setting string and returns a URI that will be accepted by {@link NtpConfig}, or * {@code null} if the string does not produce a URI considered valid. * Parses a setting string and returns a list of URIs that will be accepted by {@link * NtpConfig}, or {@code null} if the string is invalid. * * <p>The setting string is expected to be one or more server values separated by a pipe ("|") * character. * * <p>NTP server config URIs are in the form "ntp://{hostname}[:port]". This is not a registered * IANA URI scheme. * * <p>Unlike {@link #parseNtpUriStrict(String)} this method will not throw an exception. It * checks for a leading "ntp:" and will call through to {@link #parseNtpUriStrict(String)} to * attempt to parse it, returning {@code null} if it fails. To support legacy settings values, * it will also accept a string that only consists of a server name, which will be coerced into * a URI in the form "ntp://{server name}". * checks each value for a leading "ntp:" and will call through to {@link * #parseNtpUriStrict(String)} to attempt to parse it, returning {@code null} if it fails. * To support legacy settings values, it will also accept string values that only consists of a * server name, which will be coerced into a URI in the form "ntp://{server name}". */ @VisibleForTesting public static URI parseNtpServerSetting(String ntpServerSetting) { @Nullable public static List<URI> parseNtpServerSetting(@Nullable String ntpServerSetting) { if (TextUtils.isEmpty(ntpServerSetting)) { return null; } else if (ntpServerSetting.startsWith(URI_SCHEME_NTP + ":")) { } else { String[] values = ntpServerSetting.split(NTP_SETTING_SERVER_NAME_DELIMITER_REGEXP); if (values.length == 0) { return null; } List<URI> uris = new ArrayList<>(); for (String value : values) { if (value.startsWith(URI_SCHEME_NTP + ":")) { try { return parseNtpUriStrict(ntpServerSetting); uris.add(parseNtpUriStrict(value)); } catch (URISyntaxException e) { Log.w(TAG, "Rejected NTP uri setting=" + ntpServerSetting, e); return null; } } else { // This is the legacy settings path. Assumes that the string is just a host name and // creates a URI in the form ntp://<host name> // This is the legacy settings path. Assumes that the string is just a host name // and creates a URI in the form ntp://<host name> try { URI uri = new URI(URI_SCHEME_NTP, /*host=*/ntpServerSetting, URI uri = new URI(URI_SCHEME_NTP, /*host=*/value, /*path=*/null, /*fragment=*/null); // Paranoia: validate just in case the host name somehow results in a bad URI. return validateNtpServerUri(uri); // Paranoia: validate just in case the host name somehow results in a bad // URI. URI validatedUri = validateNtpServerUri(uri); uris.add(validatedUri); } catch (URISyntaxException e) { Log.w(TAG, "Rejected NTP legacy setting=" + ntpServerSetting, e); return null; } } } return uris; } } /** * Checks that the supplied URI can be used to identify an NTP server. * This method currently ignores Uri components that are not used, only checking the parts that * must be present. Returns the supplied {@code uri} if validation is successful. */ private static URI validateNtpServerUri(URI uri) throws URISyntaxException { @NonNull private static URI validateNtpServerUri(@NonNull URI uri) throws URISyntaxException { if (!uri.isAbsolute()) { throw new URISyntaxException(uri.toString(), "Relative URI not supported"); } Loading @@ -457,6 +549,8 @@ public abstract class NtpTrustedTime implements TrustedTime { public void dump(PrintWriter pw) { synchronized (this) { pw.println("getNtpConfig()=" + getNtpConfig()); pw.println("mNtpConfigForTests=" + mNtpConfigForTests); pw.println("mLastSuccessfulNtpServerUri=" + mLastSuccessfulNtpServerUri); pw.println("mTimeResult=" + mTimeResult); if (mTimeResult != null) { pw.println("mTimeResult.getAgeMillis()=" Loading Loading @@ -508,17 +602,22 @@ public abstract class NtpTrustedTime implements TrustedTime { // The Settings value has priority over static config. Check settings first. final String serverGlobalSetting = Settings.Global.getString(resolver, Settings.Global.NTP_SERVER); final URI settingsServerInfo = parseNtpServerSetting(serverGlobalSetting); final List<URI> settingsServerUris = parseNtpServerSetting(serverGlobalSetting); URI ntpServerUri; if (settingsServerInfo != null) { ntpServerUri = settingsServerInfo; List<URI> ntpServerUris; if (settingsServerUris != null) { ntpServerUris = settingsServerUris; } else { String configValue = res.getString(com.android.internal.R.string.config_ntpServer); String[] configValues = res.getStringArray(com.android.internal.R.array.config_ntpServers); try { ntpServerUri = parseNtpUriStrict(configValue); List<URI> configServerUris = new ArrayList<>(); for (String configValue : configValues) { configServerUris.add(parseNtpUriStrict(configValue)); } ntpServerUris = configServerUris; } catch (URISyntaxException e) { ntpServerUri = null; ntpServerUris = null; } } Loading @@ -526,7 +625,7 @@ public abstract class NtpTrustedTime implements TrustedTime { res.getInteger(com.android.internal.R.integer.config_ntpTimeout); final Duration timeout = Duration.ofMillis(Settings.Global.getInt( resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis)); return ntpServerUri == null ? null : new NtpConfig(ntpServerUri, timeout); return ntpServerUris == null ? null : new NtpConfig(ntpServerUris, timeout); } @Override Loading
core/res/res/values/config.xml +15 −9 Original line number Diff line number Diff line Loading @@ -2308,19 +2308,25 @@ it should be disabled in that locale's resources. --> <bool name="config_actionMenuItemAllCaps">true</bool> <!-- Remote server that can provide NTP responses. Values must be in the form: "ntp://<host>[:port]" <!-- SNTP client config: NTP servers to use to obtain an accurate time. Items must be in the form: "ntp://<host>[:port]" This is not a registered IANA URI scheme. --> <string translatable="false" name="config_ntpServer">ntp://time.android.com</string> <!-- Normal polling frequency in milliseconds --> <string-array translatable="false" name="config_ntpServers"> <item>ntp://time.android.com</item> </string-array> <!-- SNTP client config: Timeout to wait for an NTP server response in milliseconds. --> <integer name="config_ntpTimeout">5000</integer> <!-- Automatic "network" time detection config: Normal network time polling frequency in milliseconds. --> <integer name="config_ntpPollingInterval">64800000</integer> <!-- Try-again polling interval in milliseconds, in case the network request failed --> <!-- Automatic "network" time detection config: Try-again network time polling interval in milliseconds, in case the network request failed --> <integer name="config_ntpPollingIntervalShorter">60000</integer> <!-- Number of times to try again with the shorter interval, before backing off until the normal polling interval. A value < 0 indicates infinite. --> <!-- Automatic "network" time detection config: Number of times to try network time polling with the shorter interval, before backing off until the normal polling interval. A value < 0 indicates infinite. --> <integer name="config_ntpRetry">3</integer> <!-- Timeout to wait for NTP server response in milliseconds. --> <integer name="config_ntpTimeout">5000</integer> <!-- Default network policy warning threshold, in megabytes. --> <integer name="config_networkPolicyDefaultWarning">2048</integer> Loading
core/res/res/values/symbols.xml +1 −1 Original line number Diff line number Diff line Loading @@ -697,7 +697,7 @@ <java-symbol type="string" name="config_forceVoiceInteractionServicePackage" /> <java-symbol type="string" name="config_mms_user_agent" /> <java-symbol type="string" name="config_mms_user_agent_profile_url" /> <java-symbol type="string" name="config_ntpServer" /> <java-symbol type="array" name="config_ntpServers" /> <java-symbol type="string" name="config_useragentprofile_url" /> <java-symbol type="string" name="config_appsNotReportingCrashes" /> <java-symbol type="string" name="contentServiceSync" /> Loading
core/tests/coretests/src/android/util/NtpTrustedTimeTest.java +379 −97 File changed.Preview size limit exceeded, changes collapsed. Show changes