Switch NetworkTimeUpdateService to internal API

Switch NetworkTimeUpdateService to using TimeDetectorInternal instead of
the binder API.

The NetworkTimeUpdateService runs in the system server, so it does not
have to use binder to communicate with the time_detector.

Also update NetworkTimeSuggestion to include uncertainty so that it
contains all the information needed for future usecases associated with
GnssLocationProvider.

Bug: 219693030
Bug: 222295093
Test: atest services/tests/servicestests/src/com/android/server/timedetector/
Test: atest services/tests/servicestests/src/com/android/server/timezonedetector/
Test: atest core/tests/coretests/src/android/app/timedetector/
Change-Id: I4665da76429bc333b34769fc362221581472690e
This commit is contained in:
Neil Fuller
2022-06-28 14:55:11 +01:00
parent 286769a086
commit 28f3fe363b
23 changed files with 374 additions and 228 deletions

View File

@@ -22,7 +22,6 @@ import android.app.time.TimeCapabilitiesAndConfig;
import android.app.time.TimeConfiguration;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.app.timedetector.TimePoint;
@@ -49,7 +48,6 @@ interface ITimeDetectorService {
void suggestExternalTime(in ExternalTimeSuggestion timeSuggestion);
void suggestGnssTime(in GnssTimeSuggestion timeSuggestion);
boolean suggestManualTime(in ManualTimeSuggestion timeSuggestion);
void suggestNetworkTime(in NetworkTimeSuggestion timeSuggestion);
void suggestTelephonyTime(in TelephonyTimeSuggestion timeSuggestion);
TimePoint latestNetworkTime();

View File

@@ -1,19 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.timedetector;
parcelable NetworkTimeSuggestion;

View File

@@ -1,124 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.timedetector;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.ShellCommand;
import android.os.TimestampedValue;
import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
/**
* A time signal from a network time source like NTP.
*
* <p>See {@link TimeSuggestionHelper} for property information.
*
* @hide
*/
public final class NetworkTimeSuggestion implements Parcelable {
public static final @NonNull Creator<NetworkTimeSuggestion> CREATOR =
new Creator<NetworkTimeSuggestion>() {
public NetworkTimeSuggestion createFromParcel(Parcel in) {
TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel(
NetworkTimeSuggestion.class, in);
return new NetworkTimeSuggestion(helper);
}
public NetworkTimeSuggestion[] newArray(int size) {
return new NetworkTimeSuggestion[size];
}
};
@NonNull private final TimeSuggestionHelper mTimeSuggestionHelper;
public NetworkTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) {
mTimeSuggestionHelper = new TimeSuggestionHelper(
NetworkTimeSuggestion.class, unixEpochTime);
}
private NetworkTimeSuggestion(@NonNull TimeSuggestionHelper helper) {
mTimeSuggestionHelper = Objects.requireNonNull(helper);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
mTimeSuggestionHelper.handleWriteToParcel(dest, flags);
}
@NonNull
public TimestampedValue<Long> getUnixEpochTime() {
return mTimeSuggestionHelper.getUnixEpochTime();
}
@NonNull
public List<String> getDebugInfo() {
return mTimeSuggestionHelper.getDebugInfo();
}
/**
* Associates information with the instance that can be useful for debugging / logging. The
* information is present in {@link #toString()} but is not considered for {@link
* #equals(Object)} and {@link #hashCode()}.
*/
public void addDebugInfo(String... debugInfos) {
mTimeSuggestionHelper.addDebugInfo(debugInfos);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
NetworkTimeSuggestion that = (NetworkTimeSuggestion) o;
return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper);
}
@Override
public int hashCode() {
return mTimeSuggestionHelper.hashCode();
}
@Override
public String toString() {
return mTimeSuggestionHelper.handleToString();
}
/** @hide */
public static NetworkTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
throws IllegalArgumentException {
return new NetworkTimeSuggestion(
TimeSuggestionHelper.handleParseCommandLineArg(NetworkTimeSuggestion.class, cmd));
}
/** @hide */
public static void printCommandLineOpts(PrintWriter pw) {
TimeSuggestionHelper.handlePrintCommandLineOpts(pw, "Network", NetworkTimeSuggestion.class);
}
}

View File

@@ -112,14 +112,6 @@ public interface TimeDetector {
@RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE)
boolean suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
/**
* Suggests the time according to a network time source like NTP.
*
* @hide
*/
@RequiresPermission(android.Manifest.permission.SET_TIME)
void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion);
/**
* Suggests the time according to a gnss time source.
*

View File

@@ -63,18 +63,6 @@ public final class TimeDetectorImpl implements TimeDetector {
}
}
@Override
public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestNetworkTime called: " + timeSuggestion);
}
try {
mITimeDetectorService.suggestNetworkTime(timeSuggestion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
if (DEBUG) {

View File

@@ -201,7 +201,8 @@ public final class TimeSuggestionHelper {
public static void handlePrintCommandLineOpts(
@NonNull PrintWriter pw, @NonNull String typeName, @NonNull Class<?> clazz) {
pw.printf("%s suggestion options:\n", typeName);
pw.println(" --reference_time <elapsed realtime millis>");
pw.println(" --reference_time <elapsed realtime millis> - the elapsed realtime millis when"
+ " unix epoch time was read");
pw.println(" --unix_epoch_time <Unix epoch time millis>");
pw.println();
pw.println("See " + clazz.getName() + " for more information");

View File

@@ -57,13 +57,13 @@ public class NtpTrustedTime implements TrustedTime {
public static class TimeResult {
private final long mUnixEpochTimeMillis;
private final long mElapsedRealtimeMillis;
private final long mCertaintyMillis;
private final int mUncertaintyMillis;
public TimeResult(
long unixEpochTimeMillis, long elapsedRealtimeMillis, long certaintyMillis) {
long unixEpochTimeMillis, long elapsedRealtimeMillis, int uncertaintyMillis) {
mUnixEpochTimeMillis = unixEpochTimeMillis;
mElapsedRealtimeMillis = elapsedRealtimeMillis;
mCertaintyMillis = certaintyMillis;
mUncertaintyMillis = uncertaintyMillis;
}
public long getTimeMillis() {
@@ -74,8 +74,8 @@ public class NtpTrustedTime implements TrustedTime {
return mElapsedRealtimeMillis;
}
public long getCertaintyMillis() {
return mCertaintyMillis;
public int getUncertaintyMillis() {
return mUncertaintyMillis;
}
/**
@@ -102,9 +102,9 @@ public class NtpTrustedTime implements TrustedTime {
@Override
public String toString() {
return "TimeResult{"
+ "mUnixEpochTimeMillis=" + Instant.ofEpochMilli(mUnixEpochTimeMillis)
+ ", mElapsedRealtimeMillis=" + Duration.ofMillis(mElapsedRealtimeMillis)
+ ", mCertaintyMillis=" + mCertaintyMillis
+ "unixEpochTime=" + Instant.ofEpochMilli(mUnixEpochTimeMillis)
+ ", elapsedRealtime=" + Duration.ofMillis(mElapsedRealtimeMillis)
+ ", mUncertaintyMillis=" + mUncertaintyMillis
+ '}';
}
}
@@ -217,9 +217,9 @@ public class NtpTrustedTime implements TrustedTime {
final int port = connectionInfo.getPort();
final int timeoutMillis = connectionInfo.getTimeoutMillis();
if (client.requestTime(serverName, port, timeoutMillis, network)) {
long ntpCertainty = client.getRoundTripTime() / 2;
int ntpUncertaintyMillis = saturatedCast(client.getRoundTripTime() / 2);
mTimeResult = new TimeResult(
client.getNtpTime(), client.getNtpTimeReference(), ntpCertainty);
client.getNtpTime(), client.getNtpTimeReference(), ntpUncertaintyMillis);
return true;
} else {
return false;
@@ -227,6 +227,19 @@ public class NtpTrustedTime implements TrustedTime {
}
}
/**
* Casts a {@code long} to an {@code int}, clamping the value within the int range.
*/
private static int saturatedCast(long longValue) {
if (longValue > Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
}
if (longValue < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
return (int) longValue;
}
/**
* Only kept for UnsupportedAppUsage.
*

View File

@@ -29,8 +29,6 @@ import android.util.NtpTrustedTime;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.util.Date;
/**
* Handles inject NTP time to GNSS.
*
@@ -194,18 +192,18 @@ class NtpTimeHelper {
return false;
}
long time = ntpResult.getTimeMillis();
long timeReference = ntpResult.getElapsedRealtimeMillis();
long certainty = ntpResult.getCertaintyMillis();
long unixEpochTimeMillis = ntpResult.getTimeMillis();
long timeReferenceMillis = ntpResult.getElapsedRealtimeMillis();
int uncertaintyMillis = ntpResult.getUncertaintyMillis();
if (DEBUG) {
long now = System.currentTimeMillis();
Log.d(TAG, "NTP server returned: " + time + " (" + new Date(time) + ")"
+ " ntpResult: " + ntpResult + " system time offset: " + (time - now));
long currentTimeMillis = System.currentTimeMillis();
Log.d(TAG, "NTP server returned: " + unixEpochTimeMillis
+ " ntpResult: " + ntpResult
+ " system time offset: " + (unixEpochTimeMillis - currentTimeMillis));
}
// Ok to cast to int, as can't rollover in practice
mHandler.post(() -> mCallback.injectTime(time, timeReference, (int) certainty));
mHandler.post(() -> mCallback.injectTime(unixEpochTimeMillis, timeReferenceMillis,
uncertaintyMillis));
return true;
}
}

View File

@@ -0,0 +1,182 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.ShellCommand;
import android.os.TimestampedValue;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* A time signal from a network time source like NTP.
*
* <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of
* milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system. The {@code
* unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when the {@code
* unixEpochTime.value} was established. Note that the elapsed realtime clock is considered accurate
* but it is volatile, so time suggestions cannot be persisted across device resets.
*
* <p>{@code uncertaintyMillis} is an indication of error bounds associated the time. This is a
* positive value, and the correct Unix epoch time is <em>likely</em> to be within the bounds +/-
* the {@code uncertaintyMillis}. The Unix epoch time is not guaranteed to be within these bounds.
*
* <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
* record why the suggestion exists and how it was entered. This information exists only to aid in
* debugging and therefore is used by {@link #toString()}, but it is not for use in detection
* logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
*/
public final class NetworkTimeSuggestion {
@NonNull private final TimestampedValue<Long> mUnixEpochTime;
private final int mUncertaintyMillis;
@Nullable private ArrayList<String> mDebugInfo;
/**
* Create a {@link NetworkTimeSuggestion} with the supplied property values.
*
* <p>See {@link NetworkTimeSuggestion} for property details.
*/
public NetworkTimeSuggestion(
@NonNull TimestampedValue<Long> unixEpochTime, int uncertaintyMillis) {
mUnixEpochTime = Objects.requireNonNull(unixEpochTime);
if (uncertaintyMillis < 0) {
throw new IllegalArgumentException("uncertaintyMillis < 0");
}
mUncertaintyMillis = uncertaintyMillis;
}
/** See {@link NetworkTimeSuggestion} for property details. */
@NonNull
public TimestampedValue<Long> getUnixEpochTime() {
return mUnixEpochTime;
}
/** See {@link NetworkTimeSuggestion} for property details. */
public int getUncertaintyMillis() {
return mUncertaintyMillis;
}
/** See {@link NetworkTimeSuggestion} for information about {@code debugInfo}. */
@NonNull
public List<String> getDebugInfo() {
return mDebugInfo == null
? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
}
/**
* Associates information with the instance that can be useful for debugging / logging. The
* information is present in {@link #toString()} but is not considered for {@link
* #equals(Object)} and {@link #hashCode()}.
*/
public void addDebugInfo(String... debugInfos) {
if (mDebugInfo == null) {
mDebugInfo = new ArrayList<>();
}
mDebugInfo.addAll(Arrays.asList(debugInfos));
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof NetworkTimeSuggestion)) {
return false;
}
NetworkTimeSuggestion that = (NetworkTimeSuggestion) o;
return mUnixEpochTime.equals(that.mUnixEpochTime)
&& mUncertaintyMillis == that.mUncertaintyMillis;
}
@Override
public int hashCode() {
return Objects.hash(mUnixEpochTime, mUncertaintyMillis);
}
@Override
public String toString() {
return "NetworkTimeSuggestion{"
+ "mUnixEpochTime=" + mUnixEpochTime
+ "mUncertaintyMillis=" + mUncertaintyMillis
+ ", mDebugInfo=" + mDebugInfo
+ '}';
}
/** Parses command line args to create a {@link NetworkTimeSuggestion}. */
public static NetworkTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
throws IllegalArgumentException {
Long referenceTimeMillis = null;
Long unixEpochTimeMillis = null;
Integer uncertaintyMillis = null;
String opt;
while ((opt = cmd.getNextArg()) != null) {
switch (opt) {
case "--reference_time": {
referenceTimeMillis = Long.parseLong(cmd.getNextArgRequired());
break;
}
case "--unix_epoch_time": {
unixEpochTimeMillis = Long.parseLong(cmd.getNextArgRequired());
break;
}
case "--uncertainty_millis": {
uncertaintyMillis = Integer.parseInt(cmd.getNextArgRequired());
break;
}
default: {
throw new IllegalArgumentException("Unknown option: " + opt);
}
}
}
if (referenceTimeMillis == null) {
throw new IllegalArgumentException("No referenceTimeMillis specified.");
}
if (unixEpochTimeMillis == null) {
throw new IllegalArgumentException("No unixEpochTimeMillis specified.");
}
if (uncertaintyMillis == null) {
throw new IllegalArgumentException("No uncertaintyMillis specified.");
}
TimestampedValue<Long> timeSignal =
new TimestampedValue<>(referenceTimeMillis, unixEpochTimeMillis);
NetworkTimeSuggestion networkTimeSuggestion =
new NetworkTimeSuggestion(timeSignal, uncertaintyMillis);
networkTimeSuggestion.addDebugInfo("Command line injection");
return networkTimeSuggestion;
}
/** Prints the command line args needed to create a {@link NetworkTimeSuggestion}. */
public static void printCommandLineOpts(PrintWriter pw) {
pw.printf("%s suggestion options:\n", "Network");
pw.println(" --reference_time <elapsed realtime millis> - the elapsed realtime millis when"
+ " unix epoch time was read");
pw.println(" --unix_epoch_time <Unix epoch time millis>");
pw.println(" --uncertainty_millis <Uncertainty millis> - a positive error bound (+/-)"
+ " estimate for unix epoch time");
pw.println();
pw.println("See " + NetworkTimeSuggestion.class.getName() + " for more information");
}
}

View File

@@ -20,8 +20,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TimeDetector;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -48,6 +46,7 @@ import android.util.NtpTrustedTime;
import android.util.NtpTrustedTime.TimeResult;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -80,7 +79,7 @@ public class NetworkTimeUpdateService extends Binder {
private final Context mContext;
private final NtpTrustedTime mTime;
private final AlarmManager mAlarmManager;
private final TimeDetector mTimeDetector;
private final TimeDetectorInternal mTimeDetectorInternal;
private final ConnectivityManager mCM;
private final PendingIntent mPendingPollIntent;
private final PowerManager.WakeLock mWakeLock;
@@ -112,7 +111,7 @@ public class NetworkTimeUpdateService extends Binder {
mContext = context;
mTime = NtpTrustedTime.getInstance(context);
mAlarmManager = mContext.getSystemService(AlarmManager.class);
mTimeDetector = mContext.getSystemService(TimeDetector.class);
mTimeDetectorInternal = LocalServices.getService(TimeDetectorInternal.class);
mCM = mContext.getSystemService(ConnectivityManager.class);
Intent pollIntent = new Intent(ACTION_POLL, null);
@@ -272,9 +271,10 @@ public class NetworkTimeUpdateService extends Binder {
private void makeNetworkTimeSuggestion(TimeResult ntpResult, String debugInfo) {
TimestampedValue<Long> timeSignal = new TimestampedValue<>(
ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis());
NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal);
NetworkTimeSuggestion timeSuggestion =
new NetworkTimeSuggestion(timeSignal, ntpResult.getUncertaintyMillis());
timeSuggestion.addDebugInfo(debugInfo);
mTimeDetector.suggestNetworkTime(timeSuggestion);
mTimeDetectorInternal.suggestNetworkTime(timeSuggestion);
}
/**

View File

@@ -16,6 +16,8 @@
package com.android.server.timedetector;
import android.annotation.NonNull;
/**
* The internal (in-process) system server API for the {@link
* com.android.server.timedetector.TimeDetectorService}.
@@ -25,4 +27,6 @@ package com.android.server.timedetector;
*/
public interface TimeDetectorInternal {
}
/** Used to pass new network time suggestions to the time detector. */
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal);
}

View File

@@ -39,4 +39,11 @@ public class TimeDetectorInternalImpl implements TimeDetectorInternal {
mHandler = Objects.requireNonNull(handler);
mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
}
@Override
public void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
Objects.requireNonNull(timeSignal);
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
}
}

View File

@@ -27,7 +27,6 @@ import android.app.time.TimeConfiguration;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ITimeDetectorService;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.app.timedetector.TimePoint;
import android.content.Context;
@@ -295,8 +294,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
}
}
@Override
public void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
enforceSuggestNetworkTimePermission();
Objects.requireNonNull(timeSignal);

View File

@@ -32,7 +32,6 @@ import android.app.time.ExternalTimeSuggestion;
import android.app.time.TimeConfiguration;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.os.ShellCommand;
import android.os.UserHandle;

View File

@@ -22,7 +22,6 @@ import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.os.TimestampedValue;
import android.util.IndentingPrintWriter;

View File

@@ -27,7 +27,6 @@ import android.app.AlarmManager;
import android.app.time.ExternalTimeSuggestion;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.content.Context;
import android.os.Handler;

View File

@@ -189,6 +189,10 @@ public final class GeolocationTimeZoneSuggestion {
}
}
if (zoneIdsString == null) {
throw new IllegalArgumentException("Missing --zone_ids");
}
long elapsedRealtimeMillis = SystemClock.elapsedRealtime();
List<String> zoneIds = parseZoneIdsArg(zoneIdsString);
GeolocationTimeZoneSuggestion suggestion =

View File

@@ -23,7 +23,6 @@ import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.util.IndentingPrintWriter;

View File

@@ -14,11 +14,9 @@
* limitations under the License.
*/
package android.app.timedetector;
package com.android.server.timedetector;
import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
import static com.android.server.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -32,60 +30,66 @@ public class NetworkTimeSuggestionTest {
private static final TimestampedValue<Long> ARBITRARY_TIME =
new TimestampedValue<>(1111L, 2222L);
private static final int ARBITRARY_UNCERTAINTY_MILLIS = 3333;
@Test
public void testEquals() {
NetworkTimeSuggestion one = new NetworkTimeSuggestion(ARBITRARY_TIME);
NetworkTimeSuggestion one = new NetworkTimeSuggestion(
ARBITRARY_TIME, ARBITRARY_UNCERTAINTY_MILLIS);
assertEquals(one, one);
NetworkTimeSuggestion two = new NetworkTimeSuggestion(ARBITRARY_TIME);
NetworkTimeSuggestion two =
new NetworkTimeSuggestion(ARBITRARY_TIME, ARBITRARY_UNCERTAINTY_MILLIS);
assertEquals(one, two);
assertEquals(two, one);
TimestampedValue<Long> differentTime = new TimestampedValue<>(
ARBITRARY_TIME.getReferenceTimeMillis() + 1,
ARBITRARY_TIME.getValue());
NetworkTimeSuggestion three = new NetworkTimeSuggestion(differentTime);
NetworkTimeSuggestion three = new NetworkTimeSuggestion(
differentTime, ARBITRARY_UNCERTAINTY_MILLIS);
assertNotEquals(one, three);
assertNotEquals(three, one);
int differentUncertainty = ARBITRARY_UNCERTAINTY_MILLIS + 1;
NetworkTimeSuggestion four = new NetworkTimeSuggestion(
ARBITRARY_TIME, differentUncertainty);
assertNotEquals(one, four);
assertNotEquals(four, one);
// DebugInfo must not be considered in equals().
one.addDebugInfo("Debug info 1");
two.addDebugInfo("Debug info 2");
assertEquals(one, two);
}
@Test
public void testParcelable() {
NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(ARBITRARY_TIME);
assertRoundTripParcelable(suggestion);
// DebugInfo should also be stored (but is not checked by equals()
suggestion.addDebugInfo("This is debug info");
NetworkTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
}
@Test(expected = IllegalArgumentException.class)
public void testParseCommandLineArg_noReferenceTime() {
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
"--unix_epoch_time 12345");
"--unix_epoch_time 12345 --uncertainty_millis 111");
NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
}
@Test(expected = IllegalArgumentException.class)
public void testParseCommandLineArg_noUnixEpochTime() {
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
"--reference_time 54321");
"--reference_time 54321 --uncertainty_millis 111");
NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
}
@Test(expected = IllegalArgumentException.class)
public void testParseCommandLineArg_noUncertaintyMillis() {
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
"--reference_time 54321 --unix_epoch_time 12345");
NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
}
@Test
public void testParseCommandLineArg_validSuggestion() {
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
"--reference_time 54321 --unix_epoch_time 12345");
"--reference_time 54321 --unix_epoch_time 12345 --uncertainty_millis 111");
TimestampedValue<Long> timeSignal = new TimestampedValue<>(54321L, 12345L);
NetworkTimeSuggestion expectedSuggestion = new NetworkTimeSuggestion(timeSignal);
NetworkTimeSuggestion expectedSuggestion = new NetworkTimeSuggestion(timeSignal, 111);
NetworkTimeSuggestion actualSuggestion =
NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
assertEquals(expectedSuggestion, actualSuggestion);

View File

@@ -40,7 +40,6 @@ import android.app.time.ITimeDetectorListener;
import android.app.time.TimeConfiguration;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.app.timedetector.TimePoint;
import android.content.Context;
@@ -408,7 +407,7 @@ public class TimeDetectorServiceTest {
@Test
public void testLatestNetworkTime() {
NtpTrustedTime.TimeResult latestNetworkTime =
new NtpTrustedTime.TimeResult(1234L, 54321L, 999L);
new NtpTrustedTime.TimeResult(1234L, 54321L, 999);
when(mMockNtpTrustedTime.getCachedTimeResult())
.thenReturn(latestNetworkTime);
TimePoint expected = new TimePoint(latestNetworkTime.getTimeMillis(),
@@ -467,7 +466,7 @@ public class TimeDetectorServiceTest {
private static NetworkTimeSuggestion createNetworkTimeSuggestion() {
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
return new NetworkTimeSuggestion(timeValue);
return new NetworkTimeSuggestion(timeValue, 123);
}
private static GnssTimeSuggestion createGnssTimeSuggestion() {

View File

@@ -31,7 +31,6 @@ import android.annotation.UserIdInt;
import android.app.time.ExternalTimeSuggestion;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.os.TimestampedValue;
@@ -1573,7 +1572,7 @@ public class TimeDetectorStrategyImplTest {
new TimestampedValue<>(
mFakeEnvironment.peekElapsedRealtimeMillis(),
suggestedTime.toEpochMilli());
return new NetworkTimeSuggestion(unixEpochTime);
return new NetworkTimeSuggestion(unixEpochTime, 123);
}
/**

View File

@@ -16,8 +16,13 @@
package com.android.server.timezonedetector;
import static com.android.server.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import android.os.ShellCommand;
import org.junit.Test;
@@ -66,4 +71,40 @@ public class GeolocationTimeZoneSuggestionTest {
assertNotEquals(certain1v1, certain3);
assertNotEquals(certain3, certain1v1);
}
@Test(expected = IllegalArgumentException.class)
public void testParseCommandLineArg_noZoneIdsArg() {
ShellCommand testShellCommand =
createShellCommandWithArgsAndOptions(Collections.emptyList());
GeolocationTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
}
@Test
public void testParseCommandLineArg_zoneIdsUncertain() {
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
"--zone_ids UNCERTAIN");
assertNull(GeolocationTimeZoneSuggestion.parseCommandLineArg(testShellCommand)
.getZoneIds());
}
@Test
public void testParseCommandLineArg_zoneIdsEmpty() {
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions("--zone_ids EMPTY");
assertEquals(Collections.emptyList(),
GeolocationTimeZoneSuggestion.parseCommandLineArg(testShellCommand).getZoneIds());
}
@Test
public void testParseCommandLineArg_zoneIdsPresent() {
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
"--zone_ids Europe/London,Europe/Paris");
assertEquals(Arrays.asList("Europe/London", "Europe/Paris"),
GeolocationTimeZoneSuggestion.parseCommandLineArg(testShellCommand).getZoneIds());
}
@Test(expected = IllegalArgumentException.class)
public void testParseCommandLineArg_unknownArgument() {
ShellCommand testShellCommand = createShellCommandWithArgsAndOptions("--bad_arg 0");
GeolocationTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.timezonedetector;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.os.ShellCommand;
import org.mockito.stubbing.Answer;
import java.util.Arrays;
import java.util.List;
/** Utility methods related to {@link ShellCommand} objects used in several tests. */
public final class ShellCommandTestSupport {
private ShellCommandTestSupport() {}
public static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) {
return createShellCommandWithArgsAndOptions(Arrays.asList(argsWithSpaces.split(" ")));
}
public static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) {
ShellCommand command = mock(ShellCommand.class);
class ArgProvider {
private int mCount;
String getNext() {
if (mCount >= args.size()) {
return null;
}
return args.get(mCount++);
}
String getNextRequired() {
String next = getNext();
if (next == null) {
throw new IllegalArgumentException("No next");
}
return next;
}
}
ArgProvider argProvider = new ArgProvider();
when(command.getNextArg()).thenAnswer(
(Answer<String>) invocation -> argProvider.getNext());
when(command.getNextOption()).thenAnswer(
(Answer<String>) invocation -> argProvider.getNext());
when(command.getNextArgRequired()).thenAnswer(
(Answer<String>) invocation -> argProvider.getNextRequired());
return command;
}
}