Add the ability to configure NTP port for tests

Add the ability to configure NTP port for tests via the command line and
the associated plumbing / knock-ons.

In-progress CTS tests will run a fake NTP server on the device itself.
Binding to NTP's default port of 123 is restricted. Therefore, we need
to be able to override the port for tests.

adb shell cmd network_time_update_service set_server_config --port 9999
adb shell dumpsys network_time_update_service
<observe port value>
adb shell cmd network_time_update_service force_refresh
<observe false>

adb shell cmd network_time_update_service set_server_config
adb shell dumpsys network_time_update_service
<observe port value>
adb shell cmd network_time_update_service force_refresh
<observe true>

Bug: 213393821
Test: See above
Change-Id: I21e8b735fab268df0d617848b8a562f86560ad16
This commit is contained in:
Neil Fuller 2022-03-17 10:02:58 +00:00
parent 030a692189
commit 187c975af9
6 changed files with 52 additions and 16 deletions

View File

@ -60,7 +60,7 @@ public class SntpClient {
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;
private static final int NTP_PORT = 123;
public static final int STANDARD_NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_MODE_SERVER = 4;
private static final int NTP_MODE_BROADCAST = 5;
@ -108,18 +108,21 @@ public class SntpClient {
* Sends an SNTP request to the given host and processes the response.
*
* @param host host name of the server.
* @param port port of the server.
* @param timeout network timeout in milliseconds. the timeout doesn't include the DNS lookup
* time, and it applies to each individual query to the resolved addresses of
* the NTP server.
* @param network network over which to send the request.
* @return true if the transaction was successful.
*/
public boolean requestTime(String host, int timeout, Network network) {
public boolean requestTime(String host, int port, int timeout, Network network) {
final Network networkForResolv = network.getPrivateDnsBypassingCopy();
try {
final InetAddress[] addresses = networkForResolv.getAllByName(host);
for (int i = 0; i < addresses.length; i++) {
if (requestTime(addresses[i], NTP_PORT, timeout, networkForResolv)) return true;
if (requestTime(addresses[i], port, timeout, networkForResolv)) {
return true;
}
}
} catch (UnknownHostException e) {
Log.w(TAG, "Unknown host: " + host);

View File

@ -138,6 +138,10 @@ public class NtpTrustedTime implements TrustedTime {
@Nullable
private String mHostnameForTests;
/** An in-memory config override for use during tests. */
@Nullable
private Integer mPortForTests;
/** An in-memory config override for use during tests. */
@Nullable
private Duration mTimeoutForTests;
@ -163,9 +167,11 @@ public class NtpTrustedTime implements TrustedTime {
* 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) {
public void setServerConfigForTests(
@Nullable String hostname, @Nullable Integer port, @Nullable Duration timeout) {
synchronized (this) {
mHostnameForTests = hostname;
mPortForTests = port;
mTimeoutForTests = timeout;
}
}
@ -195,8 +201,9 @@ public class NtpTrustedTime implements TrustedTime {
if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
final SntpClient client = new SntpClient();
final String serverName = connectionInfo.getServer();
final int port = connectionInfo.getPort();
final int timeoutMillis = connectionInfo.getTimeoutMillis();
if (client.requestTime(serverName, timeoutMillis, network)) {
if (client.requestTime(serverName, port, timeoutMillis, network)) {
long ntpCertainty = client.getRoundTripTime() / 2;
mTimeResult = new TimeResult(
client.getNtpTime(), client.getNtpTimeReference(), ntpCertainty);
@ -297,10 +304,12 @@ public class NtpTrustedTime implements TrustedTime {
private static class NtpConnectionInfo {
@NonNull private final String mServer;
private final int mPort;
private final int mTimeoutMillis;
NtpConnectionInfo(@NonNull String server, int timeoutMillis) {
NtpConnectionInfo(@NonNull String server, int port, int timeoutMillis) {
mServer = Objects.requireNonNull(server);
mPort = port;
mTimeoutMillis = timeoutMillis;
}
@ -309,6 +318,11 @@ public class NtpTrustedTime implements TrustedTime {
return mServer;
}
@NonNull
public int getPort() {
return mPort;
}
int getTimeoutMillis() {
return mTimeoutMillis;
}
@ -317,6 +331,7 @@ public class NtpTrustedTime implements TrustedTime {
public String toString() {
return "NtpConnectionInfo{"
+ "mServer='" + mServer + '\''
+ ", mPort='" + mPort + '\''
+ ", mTimeoutMillis=" + mTimeoutMillis
+ '}';
}
@ -341,6 +356,13 @@ public class NtpTrustedTime implements TrustedTime {
}
}
final Integer port;
if (mPortForTests != null) {
port = mPortForTests;
} else {
port = SntpClient.STANDARD_NTP_PORT;
}
final int timeoutMillis;
if (mTimeoutForTests != null) {
timeoutMillis = (int) mTimeoutForTests.toMillis();
@ -350,7 +372,8 @@ public class NtpTrustedTime implements TrustedTime {
timeoutMillis = Settings.Global.getInt(
resolver, Settings.Global.NTP_TIMEOUT, defaultTimeoutMillis);
}
return TextUtils.isEmpty(hostname) ? null : new NtpConnectionInfo(hostname, timeoutMillis);
return TextUtils.isEmpty(hostname) ? null :
new NtpConnectionInfo(hostname, port, timeoutMillis);
}
/** Prints debug information. */

View File

@ -293,7 +293,8 @@ public class SntpClientTest {
@Test
public void testDnsResolutionFailure() throws Exception {
assertFalse(mClient.requestTime("ntp.server.doesnotexist.example", 5000, mNetwork));
assertFalse(mClient.requestTime("ntp.server.doesnotexist.example",
SntpClient.STANDARD_NTP_PORT, 5000, mNetwork));
}
@Test

View File

@ -196,13 +196,15 @@ public class NetworkTimeUpdateService extends Binder {
* 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) {
void setServerConfigForTests(
@Nullable String hostname, @Nullable Integer port, @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
+ ", port=" + port
+ ", timeout=" + timeout);
mTime.setServerConfigForTests(hostname, timeout);
mTime.setServerConfigForTests(hostname, port, timeout);
}
private void onPollNetworkTime(int event) {

View File

@ -46,6 +46,7 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
*/
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_PORT_ARG = "--port";
private static final String SET_SERVER_CONFIG_TIMEOUT_ARG = "--timeout_millis";
@NonNull
@ -87,6 +88,7 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
private int runSetServerConfig() {
String hostname = null;
Integer port = null;
Duration timeout = null;
String opt;
while ((opt = getNextArg()) != null) {
@ -95,6 +97,10 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
hostname = getNextArgRequired();
break;
}
case SET_SERVER_CONFIG_PORT_ARG: {
port = Integer.parseInt(getNextArgRequired());
break;
}
case SET_SERVER_CONFIG_TIMEOUT_ARG: {
timeout = Duration.ofMillis(Integer.parseInt(getNextArgRequired()));
break;
@ -104,7 +110,7 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
}
}
}
mNetworkTimeUpdateService.setServerConfigForTests(hostname, timeout);
mNetworkTimeUpdateService.setServerConfigForTests(hostname, port, timeout);
return 0;
}
@ -120,8 +126,9 @@ class NetworkTimeUpdateServiceShellCommand extends ShellCommand {
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(" Options: [%s <hostname>] [%s <port>] [%s <millis>]\n",
SET_SERVER_CONFIG_HOSTNAME_ARG, SET_SERVER_CONFIG_PORT_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();

View File

@ -24,6 +24,8 @@ import android.net.SntpClient;
import android.os.Environment;
import android.util.Log;
import libcore.io.Streams;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -37,8 +39,6 @@ import java.net.InetAddress;
import java.net.URL;
import java.util.Random;
import libcore.io.Streams;
/*
* Test Service that tries to connect to the web via different methods and outputs the results to
* the log and a output file.
@ -146,7 +146,7 @@ public class BandwidthEnforcementTestService extends IntentService {
final ConnectivityManager mCM = context.getSystemService(ConnectivityManager.class);
final Network network = mCM.getActiveNetwork();
if (client.requestTime("0.pool.ntp.org", 10000, network)) {
if (client.requestTime("0.pool.ntp.org", SntpClient.STANDARD_NTP_PORT, 10000, network)) {
return true;
}
return false;