Merge "Make TimeDetectorService more aware of origin" am: 4ef2551dfa

am: 3150e58082

Change-Id: Ia70f69e226a7800e82e29dd504351aef65048ed3
This commit is contained in:
Neil Fuller
2019-10-21 12:04:05 -07:00
committed by android-build-merger
11 changed files with 300 additions and 207 deletions

View File

@@ -16,10 +16,10 @@
package android.app.timedetector; package android.app.timedetector;
import android.app.timedetector.TimeSignal; import android.app.timedetector.PhoneTimeSuggestion;
/** /**
* System private API to comunicate with time detector service. * System private API to communicate with time detector service.
* *
* <p>Used by parts of the Android system with signals associated with the device's time to provide * <p>Used by parts of the Android system with signals associated with the device's time to provide
* information to the Time Detector Service. * information to the Time Detector Service.
@@ -32,5 +32,5 @@ import android.app.timedetector.TimeSignal;
* {@hide} * {@hide}
*/ */
interface ITimeDetectorService { interface ITimeDetectorService {
void suggestTime(in TimeSignal timeSignal); void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion);
} }

View File

@@ -16,4 +16,4 @@
package android.app.timedetector; package android.app.timedetector;
parcelable TimeSignal; parcelable PhoneTimeSuggestion;

View File

@@ -0,0 +1,137 @@
/*
* 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.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.TimestampedValue;
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 telephony source. The value consists of the number of milliseconds elapsed
* since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number
* was established. The elapsed realtime clock is considered accurate but volatile, so time signals
* must not be persisted across device resets.
*
* @hide
*/
public final class PhoneTimeSuggestion implements Parcelable {
public static final @NonNull Parcelable.Creator<PhoneTimeSuggestion> CREATOR =
new Parcelable.Creator<PhoneTimeSuggestion>() {
public PhoneTimeSuggestion createFromParcel(Parcel in) {
return PhoneTimeSuggestion.createFromParcel(in);
}
public PhoneTimeSuggestion[] newArray(int size) {
return new PhoneTimeSuggestion[size];
}
};
private final int mPhoneId;
@NonNull
private final TimestampedValue<Long> mUtcTime;
@Nullable
private ArrayList<String> mDebugInfo;
public PhoneTimeSuggestion(int phoneId, @NonNull TimestampedValue<Long> utcTime) {
mPhoneId = phoneId;
mUtcTime = Objects.requireNonNull(utcTime);
}
private static PhoneTimeSuggestion createFromParcel(Parcel in) {
int phoneId = in.readInt();
TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion(phoneId, utcTime);
@SuppressWarnings("unchecked")
ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
suggestion.mDebugInfo = debugInfo;
return suggestion;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mPhoneId);
dest.writeParcelable(mUtcTime, 0);
dest.writeList(mDebugInfo);
}
public int getPhoneId() {
return mPhoneId;
}
@NonNull
public TimestampedValue<Long> getUtcTime() {
return mUtcTime;
}
@NonNull
public List<String> getDebugInfo() {
return 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 == null || getClass() != o.getClass()) {
return false;
}
PhoneTimeSuggestion that = (PhoneTimeSuggestion) o;
return mPhoneId == that.mPhoneId
&& Objects.equals(mUtcTime, that.mUtcTime);
}
@Override
public int hashCode() {
return Objects.hash(mPhoneId, mUtcTime);
}
@Override
public String toString() {
return "PhoneTimeSuggestion{"
+ "mPhoneId='" + mPhoneId + '\''
+ ", mUtcTime=" + mUtcTime
+ ", mDebugInfo=" + mDebugInfo
+ '}';
}
}

View File

@@ -45,12 +45,12 @@ public final class TimeDetector {
* signals are available such as those that come from more reliable sources or were * signals are available such as those that come from more reliable sources or were
* determined more recently. * determined more recently.
*/ */
public void suggestTime(@NonNull TimeSignal timeSignal) { public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "suggestTime called: " + timeSignal); Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
} }
try { try {
mITimeDetectorService.suggestTime(timeSignal); mITimeDetectorService.suggestPhoneTime(timeSuggestion);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }

View File

@@ -1,109 +0,0 @@
/*
* Copyright (C) 2018 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.util.TimestampedValue;
import java.util.Objects;
/**
* A time signal from a named source. The value consists of the number of milliseconds elapsed since
* 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number was
* established. The elapsed realtime clock is considered accurate but volatile, so time signals
* must not be persisted across device resets.
*
* @hide
*/
public final class TimeSignal implements Parcelable {
public static final @android.annotation.NonNull Parcelable.Creator<TimeSignal> CREATOR =
new Parcelable.Creator<TimeSignal>() {
public TimeSignal createFromParcel(Parcel in) {
return TimeSignal.createFromParcel(in);
}
public TimeSignal[] newArray(int size) {
return new TimeSignal[size];
}
};
public static final String SOURCE_ID_NITZ = "nitz";
private final String mSourceId;
private final TimestampedValue<Long> mUtcTime;
public TimeSignal(String sourceId, TimestampedValue<Long> utcTime) {
mSourceId = Objects.requireNonNull(sourceId);
mUtcTime = Objects.requireNonNull(utcTime);
}
private static TimeSignal createFromParcel(Parcel in) {
String sourceId = in.readString();
TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
return new TimeSignal(sourceId, utcTime);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mSourceId);
dest.writeParcelable(mUtcTime, 0);
}
@NonNull
public String getSourceId() {
return mSourceId;
}
@NonNull
public TimestampedValue<Long> getUtcTime() {
return mUtcTime;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TimeSignal that = (TimeSignal) o;
return Objects.equals(mSourceId, that.mSourceId)
&& Objects.equals(mUtcTime, that.mUtcTime);
}
@Override
public int hashCode() {
return Objects.hash(mSourceId, mUtcTime);
}
@Override
public String toString() {
return "TimeSignal{"
+ "mSourceId='" + mSourceId + '\''
+ ", mUtcTime=" + mUtcTime
+ '}';
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.TimestampedValue;
import org.junit.Test;
public class PhoneTimeSuggestionTest {
private static final int PHONE_ID = 99999;
@Test
public void testEquals() {
PhoneTimeSuggestion one =
new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
assertEquals(one, one);
PhoneTimeSuggestion two =
new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
assertEquals(one, two);
assertEquals(two, one);
PhoneTimeSuggestion three =
new PhoneTimeSuggestion(PHONE_ID + 1, new TimestampedValue<>(1111L, 2222L));
assertNotEquals(one, three);
assertNotEquals(three, 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() {
PhoneTimeSuggestion one =
new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
assertEquals(one, roundTripParcelable(one));
// DebugInfo should also be stored (but is not checked by equals()
one.addDebugInfo("This is debug info");
PhoneTimeSuggestion two = roundTripParcelable(one);
assertEquals(one.getDebugInfo(), two.getDebugInfo());
}
@SuppressWarnings("unchecked")
private static <T extends Parcelable> T roundTripParcelable(T one) {
Parcel parcel = Parcel.obtain();
parcel.writeTypedObject(one, 0);
parcel.setDataPosition(0);
T toReturn = (T) parcel.readTypedObject(PhoneTimeSuggestion.CREATOR);
parcel.recycle();
return toReturn;
}
}

View File

@@ -19,7 +19,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.timedetector.TimeSignal; import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent; import android.content.Intent;
import android.util.Slog; import android.util.Slog;
import android.util.TimestampedValue; import android.util.TimestampedValue;
@@ -48,9 +48,8 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
// @NonNull after initialize() // @NonNull after initialize()
private Callback mCallback; private Callback mCallback;
// NITZ state. // Last phone suggestion.
@Nullable private TimestampedValue<Long> mLastNitzTime; @Nullable private PhoneTimeSuggestion mLastPhoneSuggestion;
// Information about the last time signal received: Used when toggling auto-time. // Information about the last time signal received: Used when toggling auto-time.
@Nullable private TimestampedValue<Long> mLastSystemClockTime; @Nullable private TimestampedValue<Long> mLastSystemClockTime;
@@ -65,46 +64,40 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
} }
@Override @Override
public void suggestTime(@NonNull TimeSignal timeSignal) { public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
if (!TimeSignal.SOURCE_ID_NITZ.equals(timeSignal.getSourceId())) {
Slog.w(TAG, "Ignoring signal from unsupported source: " + timeSignal);
return;
}
// NITZ logic // NITZ logic
TimestampedValue<Long> newNitzUtcTime = timeSignal.getUtcTime(); boolean timeSuggestionIsValid =
boolean nitzTimeIsValid = validateNewNitzTime(newNitzUtcTime, mLastNitzTime); validateNewPhoneSuggestion(timeSuggestion, mLastPhoneSuggestion);
if (!nitzTimeIsValid) { if (!timeSuggestionIsValid) {
return; return;
} }
// Always store the last NITZ value received, regardless of whether we go on to use it to // Always store the last NITZ value received, regardless of whether we go on to use it to
// update the system clock. This is so that we can validate future NITZ signals. // update the system clock. This is so that we can validate future NITZ signals.
mLastNitzTime = newNitzUtcTime; mLastPhoneSuggestion = timeSuggestion;
// System clock update logic. // System clock update logic.
// Historically, Android has sent a telephony broadcast only when setting the time using // Historically, Android has sent a telephony broadcast only when setting the time using
// NITZ. // NITZ.
final boolean sendNetworkBroadcast = final boolean sendNetworkBroadcast = true;
TimeSignal.SOURCE_ID_NITZ.equals(timeSignal.getSourceId());
final TimestampedValue<Long> newUtcTime = newNitzUtcTime; final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast); setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast);
} }
private static boolean validateNewNitzTime(TimestampedValue<Long> newNitzUtcTime, private static boolean validateNewPhoneSuggestion(@NonNull PhoneTimeSuggestion newSuggestion,
TimestampedValue<Long> lastNitzTime) { @Nullable PhoneTimeSuggestion lastSuggestion) {
if (lastNitzTime != null) { if (lastSuggestion != null) {
long referenceTimeDifference = long referenceTimeDifference = TimestampedValue.referenceTimeDifference(
TimestampedValue.referenceTimeDifference(newNitzUtcTime, lastNitzTime); newSuggestion.getUtcTime(), lastSuggestion.getUtcTime());
if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) { if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) {
// Out of order or bogus. // Out of order or bogus.
Slog.w(TAG, "validateNewNitzTime: Bad NITZ signal received." Slog.w(TAG, "validateNewNitzTime: Bad NITZ signal received."
+ " referenceTimeDifference=" + referenceTimeDifference + " referenceTimeDifference=" + referenceTimeDifference
+ " lastNitzTime=" + lastNitzTime + " lastSuggestion=" + lastSuggestion
+ " newNitzUtcTime=" + newNitzUtcTime); + " newSuggestion=" + newSuggestion);
return false; return false;
} }
} }
@@ -182,7 +175,7 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
@Override @Override
public void dump(@NonNull PrintWriter pw, @Nullable String[] args) { public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
pw.println("mLastNitzTime=" + mLastNitzTime); pw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
pw.println("mLastSystemClockTimeSet=" + mLastSystemClockTimeSet); pw.println("mLastSystemClockTimeSet=" + mLastSystemClockTimeSet);
pw.println("mLastSystemClockTime=" + mLastSystemClockTime); pw.println("mLastSystemClockTime=" + mLastSystemClockTime);
pw.println("mLastSystemClockTimeSendNetworkBroadcast=" pw.println("mLastSystemClockTimeSendNetworkBroadcast="

View File

@@ -19,7 +19,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.timedetector.ITimeDetectorService; import android.app.timedetector.ITimeDetectorService;
import android.app.timedetector.TimeSignal; import android.app.timedetector.PhoneTimeSuggestion;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.database.ContentObserver; import android.database.ContentObserver;
@@ -96,14 +96,14 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
} }
@Override @Override
public void suggestTime(@NonNull TimeSignal timeSignal) { public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSignal) {
enforceSetTimePermission(); enforceSetTimePermission();
Objects.requireNonNull(timeSignal); Objects.requireNonNull(timeSignal);
long idToken = Binder.clearCallingIdentity(); long idToken = Binder.clearCallingIdentity();
try { try {
synchronized (mStrategyLock) { synchronized (mStrategyLock) {
mTimeDetectorStrategy.suggestTime(timeSignal); mTimeDetectorStrategy.suggestPhoneTime(timeSignal);
} }
} finally { } finally {
Binder.restoreCallingIdentity(idToken); Binder.restoreCallingIdentity(idToken);

View File

@@ -18,7 +18,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.timedetector.TimeSignal; import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent; import android.content.Intent;
import android.util.TimestampedValue; import android.util.TimestampedValue;
@@ -72,7 +72,7 @@ public interface TimeDetectorStrategy {
void initialize(@NonNull Callback callback); void initialize(@NonNull Callback callback);
/** Process the suggested time. */ /** Process the suggested time. */
void suggestTime(@NonNull TimeSignal timeSignal); void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion);
/** Handle the auto-time setting being toggled on or off. */ /** Handle the auto-time setting being toggled on or off. */
void handleAutoTimeDetectionToggle(boolean enabled); void handleAutoTimeDetectionToggle(boolean enabled);

View File

@@ -23,7 +23,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import android.app.timedetector.TimeSignal; import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent; import android.content.Intent;
import android.icu.util.Calendar; import android.icu.util.Calendar;
import android.icu.util.GregorianCalendar; import android.icu.util.GregorianCalendar;
@@ -45,6 +45,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
.setActualTimeUtc(2018, 1, 1, 12, 0, 0) .setActualTimeUtc(2018, 1, 1, 12, 0, 0)
.build(); .build();
private static final int ARBITRARY_PHONE_ID = 123456;
private Script mScript; private Script mScript;
@Before @Before
@@ -53,30 +55,32 @@ public class SimpleTimeZoneDetectorStrategyTest {
} }
@Test @Test
public void testSuggestTime_nitz_timeDetectionEnabled() { public void testSuggestPhoneTime_nitz_timeDetectionEnabled() {
Scenario scenario = SCENARIO_1; Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario) mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(true); .pokeTimeDetectionEnabled(true);
TimeSignal timeSignal = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ); PhoneTimeSuggestion timeSuggestion =
scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
final int clockIncrement = 1000; final int clockIncrement = 1000;
long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement; long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
mScript.simulateTimePassing(clockIncrement) mScript.simulateTimePassing(clockIncrement)
.simulateTimeSignalReceived(timeSignal) .simulatePhoneTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis); .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis);
} }
@Test @Test
public void testSuggestTime_systemClockThreshold() { public void testSuggestPhoneTime_systemClockThreshold() {
Scenario scenario = SCENARIO_1; Scenario scenario = SCENARIO_1;
final int systemClockUpdateThresholdMillis = 1000; final int systemClockUpdateThresholdMillis = 1000;
mScript.pokeFakeClocks(scenario) mScript.pokeFakeClocks(scenario)
.pokeThresholds(systemClockUpdateThresholdMillis) .pokeThresholds(systemClockUpdateThresholdMillis)
.pokeTimeDetectionEnabled(true); .pokeTimeDetectionEnabled(true);
TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ); PhoneTimeSuggestion timeSuggestion1 =
TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime(); scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
final int clockIncrement = 100; final int clockIncrement = 100;
// Increment the the device clocks to simulate the passage of time. // Increment the the device clocks to simulate the passage of time.
@@ -86,7 +90,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
// Send the first time signal. It should be used. // Send the first time signal. It should be used.
mScript.simulateTimeSignalReceived(timeSignal1) mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis1); .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis1);
// Now send another time signal, but one that is too similar to the last one and should be // Now send another time signal, but one that is too similar to the last one and should be
@@ -95,9 +99,9 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimestampedValue<Long> utcTime2 = new TimestampedValue<>( TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
mScript.peekElapsedRealtimeMillis(), mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + underThresholdMillis); mScript.peekSystemClockMillis() + underThresholdMillis);
TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2); PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
mScript.simulateTimePassing(clockIncrement) mScript.simulateTimePassing(clockIncrement)
.simulateTimeSignalReceived(timeSignal2) .simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking(); .verifySystemClockWasNotSetAndResetCallTracking();
// Now send another time signal, but one that is on the threshold and so should be used. // Now send another time signal, but one that is on the threshold and so should be used.
@@ -105,42 +109,44 @@ public class SimpleTimeZoneDetectorStrategyTest {
mScript.peekElapsedRealtimeMillis(), mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis); mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
TimeSignal timeSignal3 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime3); PhoneTimeSuggestion timeSuggestion3 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
mScript.simulateTimePassing(clockIncrement); mScript.simulateTimePassing(clockIncrement);
long expectSystemClockMillis3 = long expectSystemClockMillis3 =
TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis()); TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
mScript.simulateTimeSignalReceived(timeSignal3) mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis3); .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis3);
} }
@Test @Test
public void testSuggestTime_nitz_timeDetectionDisabled() { public void testSuggestPhoneTime_nitz_timeDetectionDisabled() {
Scenario scenario = SCENARIO_1; Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario) mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(false); .pokeTimeDetectionEnabled(false);
TimeSignal timeSignal = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ); PhoneTimeSuggestion timeSuggestion =
mScript.simulateTimeSignalReceived(timeSignal) scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
mScript.simulatePhoneTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking(); .verifySystemClockWasNotSetAndResetCallTracking();
} }
@Test @Test
public void testSuggestTime_nitz_invalidNitzReferenceTimesIgnored() { public void testSuggestPhoneTime_nitz_invalidNitzReferenceTimesIgnored() {
Scenario scenario = SCENARIO_1; Scenario scenario = SCENARIO_1;
final int systemClockUpdateThreshold = 2000; final int systemClockUpdateThreshold = 2000;
mScript.pokeFakeClocks(scenario) mScript.pokeFakeClocks(scenario)
.pokeThresholds(systemClockUpdateThreshold) .pokeThresholds(systemClockUpdateThreshold)
.pokeTimeDetectionEnabled(true); .pokeTimeDetectionEnabled(true);
TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ); PhoneTimeSuggestion timeSuggestion1 =
TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime(); scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
// Initialize the strategy / device with a time set from NITZ. // Initialize the strategy / device with a time set from NITZ.
mScript.simulateTimePassing(100); mScript.simulateTimePassing(100);
long expectedSystemClockMillis1 = long expectedSystemClockMillis1 =
TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis()); TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
mScript.simulateTimeSignalReceived(timeSignal1) mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1); .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
// The UTC time increment should be larger than the system clock update threshold so we // The UTC time increment should be larger than the system clock update threshold so we
@@ -152,8 +158,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1; long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1;
TimestampedValue<Long> utcTime2 = new TimestampedValue<>( TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
referenceTimeBeforeLastSignalMillis, validUtcTimeMillis); referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2); PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
mScript.simulateTimeSignalReceived(timeSignal2) mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking(); .verifySystemClockWasNotSetAndResetCallTracking();
// Now supply a new signal that has an obviously bogus reference time : substantially in the // Now supply a new signal that has an obviously bogus reference time : substantially in the
@@ -162,8 +168,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1; utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1;
TimestampedValue<Long> utcTime3 = new TimestampedValue<>( TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
referenceTimeInFutureMillis, validUtcTimeMillis); referenceTimeInFutureMillis, validUtcTimeMillis);
TimeSignal timeSignal3 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime3); PhoneTimeSuggestion timeSuggestion3 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
mScript.simulateTimeSignalReceived(timeSignal3) mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
.verifySystemClockWasNotSetAndResetCallTracking(); .verifySystemClockWasNotSetAndResetCallTracking();
// Just to prove validUtcTimeMillis is valid. // Just to prove validUtcTimeMillis is valid.
@@ -172,13 +178,13 @@ public class SimpleTimeZoneDetectorStrategyTest {
validReferenceTimeMillis, validUtcTimeMillis); validReferenceTimeMillis, validUtcTimeMillis);
long expectedSystemClockMillis4 = long expectedSystemClockMillis4 =
TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis()); TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
TimeSignal timeSignal4 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime4); PhoneTimeSuggestion timeSuggestion4 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
mScript.simulateTimeSignalReceived(timeSignal4) mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4); .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4);
} }
@Test @Test
public void testSuggestTime_timeDetectionToggled() { public void testSuggestPhoneTime_timeDetectionToggled() {
Scenario scenario = SCENARIO_1; Scenario scenario = SCENARIO_1;
final int clockIncrementMillis = 100; final int clockIncrementMillis = 100;
final int systemClockUpdateThreshold = 2000; final int systemClockUpdateThreshold = 2000;
@@ -186,15 +192,16 @@ public class SimpleTimeZoneDetectorStrategyTest {
.pokeThresholds(systemClockUpdateThreshold) .pokeThresholds(systemClockUpdateThreshold)
.pokeTimeDetectionEnabled(false); .pokeTimeDetectionEnabled(false);
TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ); PhoneTimeSuggestion timeSuggestion1 =
TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime(); scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
// Simulate time passing. // Simulate time passing.
mScript.simulateTimePassing(clockIncrementMillis); mScript.simulateTimePassing(clockIncrementMillis);
// Simulate the time signal being received. It should not be used because auto time // Simulate the time signal being received. It should not be used because auto time
// detection is off but it should be recorded. // detection is off but it should be recorded.
mScript.simulateTimeSignalReceived(timeSignal1) mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasNotSetAndResetCallTracking(); .verifySystemClockWasNotSetAndResetCallTracking();
// Simulate more time passing. // Simulate more time passing.
@@ -216,7 +223,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimestampedValue<Long> utcTime2 = new TimestampedValue<>( TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
mScript.peekElapsedRealtimeMillis(), mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + systemClockUpdateThreshold); mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2); PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
// Simulate more time passing. // Simulate more time passing.
mScript.simulateTimePassing(clockIncrementMillis); mScript.simulateTimePassing(clockIncrementMillis);
@@ -226,7 +233,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
// The new time, though valid, should not be set in the system clock because auto time is // The new time, though valid, should not be set in the system clock because auto time is
// disabled. // disabled.
mScript.simulateTimeSignalReceived(timeSignal2) mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking(); .verifySystemClockWasNotSetAndResetCallTracking();
// Turn on auto time detection. // Turn on auto time detection.
@@ -234,17 +241,6 @@ public class SimpleTimeZoneDetectorStrategyTest {
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2); .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2);
} }
@Test
public void testSuggestTime_unknownSource() {
Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(true);
TimeSignal timeSignal = scenario.createTimeSignalForActual("unknown");
mScript.simulateTimeSignalReceived(timeSignal)
.verifySystemClockWasNotSetAndResetCallTracking();
}
/** /**
* A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving * A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
* like the real thing should, it also asserts preconditions. * like the real thing should, it also asserts preconditions.
@@ -407,8 +403,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
return mFakeCallback.peekSystemClockMillis(); return mFakeCallback.peekSystemClockMillis();
} }
Script simulateTimeSignalReceived(TimeSignal timeSignal) { Script simulatePhoneTimeSuggestion(PhoneTimeSuggestion timeSuggestion) {
mSimpleTimeDetectorStrategy.suggestTime(timeSignal); mSimpleTimeDetectorStrategy.suggestPhoneTime(timeSuggestion);
return this; return this;
} }
@@ -466,10 +462,10 @@ public class SimpleTimeZoneDetectorStrategyTest {
return mActualTimeMillis; return mActualTimeMillis;
} }
TimeSignal createTimeSignalForActual(String sourceId) { PhoneTimeSuggestion createPhoneTimeSuggestionForActual(int phoneId) {
TimestampedValue<Long> time = new TimestampedValue<>( TimestampedValue<Long> time = new TimestampedValue<>(
mInitialDeviceRealtimeMillis, mActualTimeMillis); mInitialDeviceRealtimeMillis, mActualTimeMillis);
return new TimeSignal(sourceId, time); return new PhoneTimeSuggestion(phoneId, time);
} }
static class Builder { static class Builder {

View File

@@ -28,7 +28,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.timedetector.TimeSignal; import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.util.TimestampedValue; import android.util.TimestampedValue;
@@ -67,10 +67,10 @@ public class TimeDetectorServiceTest {
public void testStubbedCall_withoutPermission() { public void testStubbedCall_withoutPermission() {
doThrow(new SecurityException("Mock")) doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingPermission(anyString(), any()); .when(mMockContext).enforceCallingPermission(anyString(), any());
TimeSignal timeSignal = createNitzTimeSignal(); PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
try { try {
mTimeDetectorService.suggestTime(timeSignal); mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
} finally { } finally {
verify(mMockContext).enforceCallingPermission( verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SET_TIME), anyString()); eq(android.Manifest.permission.SET_TIME), anyString());
@@ -78,15 +78,15 @@ public class TimeDetectorServiceTest {
} }
@Test @Test
public void testSuggestTime() { public void testSuggestPhoneTime() {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any()); doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
TimeSignal timeSignal = createNitzTimeSignal(); PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
mTimeDetectorService.suggestTime(timeSignal); mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
verify(mMockContext) verify(mMockContext)
.enforceCallingPermission(eq(android.Manifest.permission.SET_TIME), anyString()); .enforceCallingPermission(eq(android.Manifest.permission.SET_TIME), anyString());
mStubbedTimeDetectorStrategy.verifySuggestTimeCalled(timeSignal); mStubbedTimeDetectorStrategy.verifySuggestPhoneTimeCalled(phoneTimeSuggestion);
} }
@Test @Test
@@ -115,15 +115,16 @@ public class TimeDetectorServiceTest {
mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(false); mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(false);
} }
private static TimeSignal createNitzTimeSignal() { private static PhoneTimeSuggestion createPhoneTimeSuggestion() {
int phoneId = 1234;
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L); TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
return new TimeSignal(TimeSignal.SOURCE_ID_NITZ, timeValue); return new PhoneTimeSuggestion(phoneId, timeValue);
} }
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy { private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
// Call tracking. // Call tracking.
private TimeSignal mLastSuggestedTime; private PhoneTimeSuggestion mLastPhoneSuggestion;
private Boolean mLastAutoTimeDetectionToggle; private Boolean mLastAutoTimeDetectionToggle;
private boolean mDumpCalled; private boolean mDumpCalled;
@@ -132,9 +133,9 @@ public class TimeDetectorServiceTest {
} }
@Override @Override
public void suggestTime(TimeSignal timeSignal) { public void suggestPhoneTime(PhoneTimeSuggestion timeSuggestion) {
resetCallTracking(); resetCallTracking();
mLastSuggestedTime = timeSignal; mLastPhoneSuggestion = timeSuggestion;
} }
@Override @Override
@@ -150,13 +151,13 @@ public class TimeDetectorServiceTest {
} }
void resetCallTracking() { void resetCallTracking() {
mLastSuggestedTime = null; mLastPhoneSuggestion = null;
mLastAutoTimeDetectionToggle = null; mLastAutoTimeDetectionToggle = null;
mDumpCalled = false; mDumpCalled = false;
} }
void verifySuggestTimeCalled(TimeSignal expectedSignal) { void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSignal) {
assertEquals(expectedSignal, mLastSuggestedTime); assertEquals(expectedSignal, mLastPhoneSuggestion);
} }
void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) { void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) {