Move suggestExternalTime to TimeManager

This CL moves suggestExternalTime method from TimeDetector to
TimeManager. Eventual goal is to make suggestExternalTime a System
API. Ideally all time related system APIs live in android.app.time
hence the move.

Test: atest android.app.time
Change-Id: I464545e77fdf68c35c8a338bfe5ac8b7535bc3e6
Bug: 177079827
This commit is contained in:
Mustafa Acer
2021-02-09 07:35:07 +00:00
parent 377af2a8bc
commit e4d26ca32c
7 changed files with 79 additions and 58 deletions

View File

@@ -16,6 +16,8 @@
package android.app.time;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
@@ -31,9 +33,9 @@ import java.util.Objects;
/**
* A time signal from an External source.
*
* External time suggestions are for use in situations where the Android device is part of a wider
* network of devices that are required to use a single time source, and where authority for the
* time is external to the Android device. For example, for the Android Auto use case where the
* <p>External time suggestions are for use in situations where the Android device is part of a
* wider network of devices that are required to use a single time source, and where authority for
* the time is external to the Android device. For example, for the Android Auto use case where the
* Android device is part of a wider in-car network of devices that should display the same time.
*
* <p>Android allows for a single external source for time. If there are several external sources
@@ -49,19 +51,19 @@ import java.util.Objects;
* capture the elapsed realtime reference clock, e.g. via {@link SystemClock#elapsedRealtime()},
* when the UTC time is first obtained (usually under a wakelock). This enables Android to adjust
* for latency introduced between suggestion creation and eventual use. Adjustments for other
* sources of latency, i.e. those before the external time suggestion is created, must be handled
* by the creator.
* sources of latency, i.e. those before the external time suggestion is created, must be handled by
* the creator.
*
* <p>{@code utcTime} is the suggested time. The {@code utcTime.value} is the number of milliseconds
* elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the value of the
* elapsed realtime clock when the {@code utcTime.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 elapsedRealtimeMillis} and {@code suggestionMillis} represent the suggested time.
* {@code suggestionMillis} is the number of milliseconds elapsed since 1/1/1970 00:00:00 UTC.
* {@code elapsedRealtimeMillis} is the value of the elapsed realtime clock when {@code
* suggestionMillis} 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 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)}.
* 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)}.
*
* @hide
*/
@@ -78,17 +80,28 @@ public final class ExternalTimeSuggestion implements Parcelable {
}
};
@NonNull private final TimestampedValue<Long> mUtcTime;
@Nullable private ArrayList<String> mDebugInfo;
@NonNull
private final TimestampedValue<Long> mUtcTime;
@Nullable
private ArrayList<String> mDebugInfo;
public ExternalTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
mUtcTime = Objects.requireNonNull(utcTime);
Objects.requireNonNull(utcTime.getValue());
/**
* Creates a time suggestion cross-referenced to the elapsed realtime clock. See {@link
* ExternalTimeSuggestion} for more details.
*
* @param elapsedRealtimeMillis the elapsed realtime clock reference for the suggestion
* @param suggestionMillis the suggested UTC time in milliseconds since the start of the
* Unix epoch
*/
public ExternalTimeSuggestion(@ElapsedRealtimeLong long elapsedRealtimeMillis,
@CurrentTimeMillisLong long suggestionMillis) {
mUtcTime = new TimestampedValue(elapsedRealtimeMillis, suggestionMillis);
}
private static ExternalTimeSuggestion createFromParcel(Parcel in) {
TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
ExternalTimeSuggestion suggestion = new ExternalTimeSuggestion(utcTime);
ExternalTimeSuggestion suggestion =
new ExternalTimeSuggestion(utcTime.getReferenceTimeMillis(), utcTime.getValue());
@SuppressWarnings("unchecked")
ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
suggestion.mDebugInfo = debugInfo;
@@ -106,23 +119,31 @@ public final class ExternalTimeSuggestion implements Parcelable {
dest.writeList(mDebugInfo);
}
/**
* {@hide}
*/
@NonNull
public TimestampedValue<Long> getUtcTime() {
return mUtcTime;
}
/**
* Returns information that can be useful for debugging / logging. See {@link #addDebugInfo}.
* {@hide}
*/
@NonNull
public List<String> getDebugInfo() {
return mDebugInfo == null
? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
? 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()}.
* information is present in {@link #toString()} but is not considered for {@link
* #equals(Object)} and {@link #hashCode()}.
*/
public void addDebugInfo(String... debugInfos) {
public void addDebugInfo(@NonNull String... debugInfos) {
if (mDebugInfo == null) {
mDebugInfo = new ArrayList<>();
}
@@ -148,9 +169,7 @@ public final class ExternalTimeSuggestion implements Parcelable {
@Override
public String toString() {
return "ExternalTimeSuggestion{"
+ "mUtcTime=" + mUtcTime
+ ", mDebugInfo=" + mDebugInfo
return "ExternalTimeSuggestion{" + "mUtcTime=" + mUtcTime + ", mDebugInfo=" + mDebugInfo
+ '}';
}
}

View File

@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.timedetector.ITimeDetectorService;
import android.app.timezonedetector.ITimeZoneDetectorService;
import android.content.Context;
import android.os.RemoteException;
@@ -45,6 +46,7 @@ public final class TimeManager {
private final Object mLock = new Object();
private final ITimeZoneDetectorService mITimeZoneDetectorService;
private final ITimeDetectorService mITimeDetectorService;
@GuardedBy("mLock")
private ITimeZoneDetectorListener mTimeZoneDetectorReceiver;
@@ -62,6 +64,8 @@ public final class TimeManager {
// internal refactoring.
mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
mITimeDetectorService = ITimeDetectorService.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.TIME_DETECTOR_SERVICE));
}
/**
@@ -214,4 +218,23 @@ public final class TimeManager {
}
}
}
/**
* Suggests the current time from an external time source. For example, a form factor-specific
* HAL. This time <em>may</em> be used to set the device system clock, depending on the device
* configuration and user settings. This method call is processed asynchronously.
* See {@link ExternalTimeSuggestion} for more details.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.SET_TIME)
public void suggestExternalTime(@NonNull ExternalTimeSuggestion timeSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestExternalTime called: " + timeSuggestion);
}
try {
mITimeDetectorService.suggestExternalTime(timeSuggestion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}

View File

@@ -19,7 +19,6 @@ package android.app.timedetector;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.app.time.ExternalTimeSuggestion;
import android.content.Context;
import android.os.SystemClock;
import android.os.TimestampedValue;
@@ -80,12 +79,4 @@ public interface TimeDetector {
*/
@RequiresPermission(android.Manifest.permission.SET_TIME)
void suggestGnssTime(GnssTimeSuggestion timeSuggestion);
/**
* Suggests the time according to an external time source (form factor specific HAL, etc).
*
* @hide
*/
@RequiresPermission(android.Manifest.permission.SET_TIME)
void suggestExternalTime(ExternalTimeSuggestion timeSuggestion);
}

View File

@@ -17,7 +17,6 @@
package android.app.timedetector;
import android.annotation.NonNull;
import android.app.time.ExternalTimeSuggestion;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -87,16 +86,4 @@ public final class TimeDetectorImpl implements TimeDetector {
throw e.rethrowFromSystemServer();
}
}
@Override
public void suggestExternalTime(ExternalTimeSuggestion timeSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestExternalTime called: " + timeSuggestion);
}
try {
mITimeDetectorService.suggestExternalTime(timeSuggestion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}

View File

@@ -33,17 +33,20 @@ public class ExternalTimeSuggestionTest {
@Test
public void testEquals() {
ExternalTimeSuggestion one = new ExternalTimeSuggestion(ARBITRARY_TIME);
ExternalTimeSuggestion one = new ExternalTimeSuggestion(
ARBITRARY_TIME.getReferenceTimeMillis(),
ARBITRARY_TIME.getValue());
assertEquals(one, one);
ExternalTimeSuggestion two = new ExternalTimeSuggestion(ARBITRARY_TIME);
ExternalTimeSuggestion two = new ExternalTimeSuggestion(
ARBITRARY_TIME.getReferenceTimeMillis(),
ARBITRARY_TIME.getValue());
assertEquals(one, two);
assertEquals(two, one);
TimestampedValue<Long> differentTime = new TimestampedValue<>(
ExternalTimeSuggestion three = new ExternalTimeSuggestion(
ARBITRARY_TIME.getReferenceTimeMillis() + 1,
ARBITRARY_TIME.getValue());
ExternalTimeSuggestion three = new ExternalTimeSuggestion(differentTime);
assertNotEquals(one, three);
assertNotEquals(three, one);
@@ -55,7 +58,9 @@ public class ExternalTimeSuggestionTest {
@Test
public void testParcelable() {
ExternalTimeSuggestion suggestion = new ExternalTimeSuggestion(ARBITRARY_TIME);
ExternalTimeSuggestion suggestion = new ExternalTimeSuggestion(
ARBITRARY_TIME.getReferenceTimeMillis(),
ARBITRARY_TIME.getValue());
assertRoundTripParcelable(suggestion);
// DebugInfo should also be stored (but is not checked by equals())

View File

@@ -287,8 +287,7 @@ public class TimeDetectorServiceTest {
}
private static ExternalTimeSuggestion createExternalTimeSuggestion() {
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
return new ExternalTimeSuggestion(timeValue);
return new ExternalTimeSuggestion(100L, 1_000_000L);
}
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {

View File

@@ -1483,11 +1483,8 @@ public class TimeDetectorStrategyImplTest {
* reference time.
*/
ExternalTimeSuggestion generateExternalTimeSuggestion(Instant suggestedTime) {
TimestampedValue<Long> utcTime =
new TimestampedValue<>(
mFakeEnvironment.peekElapsedRealtimeMillis(),
return new ExternalTimeSuggestion(mFakeEnvironment.peekElapsedRealtimeMillis(),
suggestedTime.toEpochMilli());
return new ExternalTimeSuggestion(utcTime);
}
/**