Loading src/java/com/android/internal/telephony/NitzStateMachine.java +176 −107 Original line number Diff line number Diff line Loading @@ -98,6 +98,13 @@ public class NitzStateMachine { return ignoreNitz != null && ignoreNitz.equals("yes"); } /** * Returns the same value as {@link System#currentTimeMillis()}. */ public long currentTimeMillis() { return System.currentTimeMillis(); } /** * Returns the same value as {@link SystemClock#elapsedRealtime()}. */ Loading @@ -110,6 +117,31 @@ public class NitzStateMachine { } } /** A pair containing a value and an associated time stamp. */ private static class TimeStampedValue<T> { /** The value. */ final T mValue; /** * The value of {@link SystemClock#elapsedRealtime} or equivalent when value was * determined. */ final long mElapsedRealtime; TimeStampedValue(T value, long elapsedRealtime) { this.mValue = value; this.mElapsedRealtime = elapsedRealtime; } @Override public String toString() { return "TimeStampedValue{" + "mValue=" + mValue + ", mElapsedRealtime=" + mElapsedRealtime + '}'; } } private static final String LOG_TAG = ServiceStateTracker.LOG_TAG; private static final boolean DBG = ServiceStateTracker.DBG; Loading Loading @@ -142,8 +174,16 @@ public class NitzStateMachine { "tg", // Togo }; private final LocalLog mTimeLog = new LocalLog(15); private final LocalLog mTimeZoneLog = new LocalLog(15); // Time detection state. /** * The last NITZ-sourced time considered. If auto time detection was off at the time this may * not have been used to set the device time, but it can be used if auto time detection is * re-enabled. */ private TimeStampedValue<Long> mSavedNitzTime; // Time Zone detection state. /** * Sometimes we get the NITZ time before we know what country we Loading @@ -155,19 +195,26 @@ public class NitzStateMachine { private NitzData mNitzData; private boolean mGotCountryCode = false; private String mSavedTimeZoneId; private long mSavedTime; private long mSavedAtTime; /** Wake lock used while setting time of day. */ private PowerManager.WakeLock mWakeLock; private static final String WAKELOCK_TAG = "NitzStateMachine"; /** Boolean is true if setTimeFromNITZ was called */ private boolean mNitzUpdatedTime = false; /** * Boolean is {@code true} if {@link #setTimeZoneFromNitz(NitzData, long)} has been called and * was able to determine a time zone (which may not ultimately have been used due to user * settings). Cleared by {@link #clearNitzTimeZoneDetectionSuccessful()}, * The flag can be used when historic NITZ data may no longer be valid. {@code true} indicates * it's not reasonable to try to set the time zone using less reliable algorithms than * NITZ-based detection such as by just using network country code. */ private boolean mNitzTimeZoneDetectionSuccessful = false; // Miscellaneous dependencies and helpers not related to detection state. private final LocalLog mTimeLog = new LocalLog(15); private final LocalLog mTimeZoneLog = new LocalLog(15); private final GsmCdmaPhone mPhone; private final DeviceState mDeviceState; private final TimeServiceHelper mTimeServiceHelper; /** Wake lock used while setting time of day. */ private final PowerManager.WakeLock mWakeLock; private static final String WAKELOCK_TAG = "NitzStateMachine"; public NitzStateMachine(GsmCdmaPhone phone) { this(phone, Loading Loading @@ -251,7 +298,11 @@ public class NitzStateMachine { // a zero UTC offset) the device will retain the existing time zone setting and not try // to derive one from the isoCountryCode. if (mNeedFixZoneAfterNitz) { long ctm = System.currentTimeMillis(); try { // Acquire the wakelock as we're reading the system clock here. mWakeLock.acquire(); long ctm = mDeviceState.currentTimeMillis(); long tzOffset = zone.getOffset(ctm); if (DBG) { Rlog.d(LOG_TAG, "fixTimeZone: tzOffset=" + tzOffset Loading @@ -259,17 +310,19 @@ public class NitzStateMachine { } if (mTimeServiceHelper.isTimeDetectionEnabled()) { long adj = ctm - tzOffset; if (DBG) { Rlog.d(LOG_TAG, "fixTimeZone: adj ltod=" + TimeUtils.logTimeOfDay(adj)); } setAndBroadcastNetworkSetTime(adj); String msg = "fixTimeZone: adj ltod=" + TimeUtils.logTimeOfDay(adj); setAndBroadcastNetworkSetTime(msg, adj); } else { // Adjust the saved NITZ time to account for tzOffset. mSavedTime = mSavedTime - tzOffset; mSavedNitzTime = new TimeStampedValue<>( mSavedNitzTime.mValue - tzOffset, mSavedNitzTime.mElapsedRealtime); if (DBG) { Rlog.d(LOG_TAG, "fixTimeZone: adj mSavedTime=" + mSavedTime); Rlog.d(LOG_TAG, "fixTimeZone: adj mSavedTime=" + mSavedNitzTime); } } } finally { mWakeLock.release(); } } if (DBG) { Rlog.d(LOG_TAG, "fixTimeZone: using default TimeZone"); Loading Loading @@ -327,7 +380,10 @@ public class NitzStateMachine { */ public void setTimeAndTimeZoneFromNitz(NitzData newNitzData, long nitzReceiveTime) { setTimeZoneFromNitz(newNitzData, nitzReceiveTime); setTimeFromNitz(newNitzData, nitzReceiveTime); TimeStampedValue<NitzData> nitzSignal = new TimeStampedValue<>(newNitzData, nitzReceiveTime); setTimeFromNitz(nitzSignal); } private void setTimeZoneFromNitz(NitzData newNitzData, long nitzReceiveTime) { Loading Loading @@ -395,6 +451,7 @@ public class NitzStateMachine { if (mTimeServiceHelper.isTimeZoneDetectionEnabled()) { setAndBroadcastNetworkSetTimeZone(zone.getID()); } mNitzTimeZoneDetectionSuccessful = true; saveNitzTimeZone(zone.getID()); } } catch (RuntimeException ex) { Loading @@ -402,84 +459,84 @@ public class NitzStateMachine { } } private void setTimeFromNitz(NitzData newNitzData, long nitzReceiveTime) { private void setTimeFromNitz(TimeStampedValue<NitzData> nitzTimeSignal) { try { boolean ignoreNitz = mDeviceState.getIgnoreNitz(); if (ignoreNitz) { Rlog.d(LOG_TAG, "NITZ: Not setting clock because gsm.ignore-nitz is set"); Rlog.d(LOG_TAG, "setTimeFromNitz: Not setting clock because gsm.ignore-nitz is set"); return; } try { // Acquire the wake lock as we are reading the elapsed realtime clock and system // clock. mWakeLock.acquire(); long millisSinceNitzReceived = mDeviceState.elapsedRealtime() - nitzReceiveTime; if (millisSinceNitzReceived < 0) { // Sanity check: something is wrong if (DBG) { Rlog.d(LOG_TAG, "NITZ: not setting time, clock has rolled " + "backwards since NITZ time was received, " + newNitzData); } return; } if (millisSinceNitzReceived > Integer.MAX_VALUE) { // If the time is this far off, something is wrong > 24 days! // Validate the nitzTimeSignal to reject obviously bogus elapsedRealtime values. long elapsedRealtime = mDeviceState.elapsedRealtime(); long millisSinceNitzReceived = elapsedRealtime - nitzTimeSignal.mElapsedRealtime; if (millisSinceNitzReceived < 0 || millisSinceNitzReceived > Integer.MAX_VALUE) { if (DBG) { Rlog.d(LOG_TAG, "NITZ: not setting time, processing has taken " + (millisSinceNitzReceived / (1000 * 60 * 60 * 24)) + " days"); Rlog.d(LOG_TAG, "setTimeFromNitz: not setting time, unexpected" + " elapsedRealtime=" + elapsedRealtime + " nitzTimeSignal=" + nitzTimeSignal); } return; } // Adjust the NITZ time by the delay since it was received. long adjustedCurrentTimeMillis = newNitzData.getCurrentTimeInMillis(); adjustedCurrentTimeMillis += millisSinceNitzReceived; // Adjust the NITZ time by the delay since it was received to get the time now. long adjustedCurrentTimeMillis = nitzTimeSignal.mValue.getCurrentTimeInMillis() + millisSinceNitzReceived; long gained = adjustedCurrentTimeMillis - mDeviceState.currentTimeMillis(); if (mTimeServiceHelper.isTimeDetectionEnabled()) { String tmpLog = "NITZ: newNitaData=" + newNitzData + " nitzReceiveTime=" + nitzReceiveTime + " Setting time of day to " + adjustedCurrentTimeMillis + " NITZ receive delay(ms): " + millisSinceNitzReceived + " gained(ms): " + (adjustedCurrentTimeMillis - System.currentTimeMillis()); if (DBG) { Rlog.d(LOG_TAG, tmpLog); } mTimeLog.log(tmpLog); // Update system time automatically long gained = adjustedCurrentTimeMillis - System.currentTimeMillis(); long timeSinceLastUpdate = mDeviceState.elapsedRealtime() - mSavedAtTime; String logMsg = "(setTimeFromNitz)" + " nitzTimeSignal=" + nitzTimeSignal + " adjustedCurrentTimeMillis=" + adjustedCurrentTimeMillis + " millisSinceNitzReceived= " + millisSinceNitzReceived + " gained=" + gained; if (mSavedNitzTime == null) { logMsg += ": First update received."; setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis); } else { long elapsedRealtimeSinceLastSaved = mDeviceState.elapsedRealtime() - mSavedNitzTime.mElapsedRealtime; int nitzUpdateSpacing = mDeviceState.getNitzUpdateSpacingMillis(); int nitzUpdateDiff = mDeviceState.getNitzUpdateDiffMillis(); if ((mSavedAtTime == 0) || (timeSinceLastUpdate > nitzUpdateSpacing) || (Math.abs(gained) > nitzUpdateDiff)) { if (DBG) { Rlog.d(LOG_TAG, "NITZ: Auto updating time of day to " + adjustedCurrentTimeMillis + " NITZ receive delay=" + millisSinceNitzReceived + "ms gained=" + gained + "ms from " + newNitzData); } setAndBroadcastNetworkSetTime(adjustedCurrentTimeMillis); if (elapsedRealtimeSinceLastSaved > nitzUpdateSpacing || Math.abs(gained) > nitzUpdateDiff) { // Either it has been a while since we received an update, or the gain // is sufficiently large that we want to act on it. logMsg += ": New update received."; setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis); } else { if (DBG) { Rlog.d(LOG_TAG, "NITZ: ignore, a previous update was " + timeSinceLastUpdate + "ms ago and gained=" + gained + "ms"); Rlog.d(LOG_TAG, logMsg + ": Update throttled."); } // Return early. This means that we don't reset the // mSavedNitzTime for next time and that we may act on more // NITZ time signals overall but should end up with a system clock that // tracks NITZ more closely than if we saved throttled values (which // would reset mSavedNitzTime.elapsedRealtime used to calculate time // since the last NITZ signal was received). return; } } saveNitzTime(adjustedCurrentTimeMillis); } // Save the last NITZ time signal used so we can return to it later // if auto-time detection is toggled. mSavedNitzTime = new TimeStampedValue<>( adjustedCurrentTimeMillis, nitzTimeSignal.mElapsedRealtime); } finally { mWakeLock.release(); } } catch (RuntimeException ex) { Rlog.e(LOG_TAG, "NITZ: Processing NITZ data " + newNitzData + " ex=" + ex); Rlog.e(LOG_TAG, "setTimeFromNitz: Processing NITZ data " + nitzTimeSignal + " ex=" + ex); } } Loading @@ -487,12 +544,6 @@ public class NitzStateMachine { mSavedTimeZoneId = zoneId; } private void saveNitzTime(long time) { mSavedTime = time; mSavedAtTime = mDeviceState.elapsedRealtime(); mNitzUpdatedTime = true; } private void setAndBroadcastNetworkSetTimeZone(String zoneId) { if (DBG) { Rlog.d(LOG_TAG, "setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId); Loading @@ -505,24 +556,38 @@ public class NitzStateMachine { } } private void setAndBroadcastNetworkSetTime(long time) { private void setAndBroadcastNetworkSetTime(String msg, long time) { if (!mWakeLock.isHeld()) { Rlog.w(LOG_TAG, "Wake lock not held while setting device time (msg=" + msg + ")"); } msg = "setAndBroadcastNetworkSetTime: [setting time to time=" + time + "]:" + msg; if (DBG) { Rlog.d(LOG_TAG, "setAndBroadcastNetworkSetTime: time=" + time + "ms"); Rlog.d(LOG_TAG, msg); } mTimeLog.log(msg); mTimeServiceHelper.setDeviceTime(time); TelephonyMetrics.getInstance().writeNITZEvent(mPhone.getPhoneId(), time); } private void revertToNitzTime() { if (DBG) { Rlog.d(LOG_TAG, "Reverting to NITZ Time: mSavedTime=" + mSavedTime + " mSavedAtTime=" + mSavedAtTime); Rlog.d(LOG_TAG, "Reverting to NITZ Time: mSavedTime=" + mSavedNitzTime); } if (mSavedNitzTime != null) { try { // Acquire the wakelock as we're reading the elapsed realtime clock here. mWakeLock.acquire(); long elapsedRealtime = mDeviceState.elapsedRealtime(); String msg = "Reverting to NITZ time, elapsedRealtime=" + elapsedRealtime + " mSavedNitzTime=" + mSavedNitzTime; long adjustedCurrentTimeMillis = mSavedNitzTime.mValue + (elapsedRealtime - mSavedNitzTime.mElapsedRealtime); setAndBroadcastNetworkSetTime(msg, adjustedCurrentTimeMillis); } finally { mWakeLock.release(); } if (mSavedTime != 0 && mSavedAtTime != 0) { long currTime = mDeviceState.elapsedRealtime(); mTimeLog.log("Reverting to NITZ time, currTime=" + currTime + " mSavedAtTime=" + mSavedAtTime + " mSavedTime=" + mSavedTime); setAndBroadcastNetworkSetTime(mSavedTime + (currTime - mSavedAtTime)); } } Loading @@ -546,14 +611,18 @@ public class NitzStateMachine { * Dumps the current in-memory state to the supplied PrintWriter. */ public void dumpState(PrintWriter pw) { // Time Detection State pw.println(" mSavedTime=" + mSavedNitzTime); // Time Zone Detection State pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz); pw.println(" mNitzData=" + mNitzData); pw.println(" mGotCountryCode=" + mGotCountryCode); pw.println(" mSavedTimeZone=" + mSavedTimeZoneId); pw.println(" mSavedTime=" + mSavedTime); pw.println(" mSavedAtTime=" + mSavedAtTime); pw.println(" mNitzTimeZoneDetectionSuccessful=" + mNitzTimeZoneDetectionSuccessful); // Miscellaneous pw.println(" mWakeLock=" + mWakeLock); pw.println(" mNitzUpdatedTime=" + mNitzUpdatedTime); pw.flush(); } Loading Loading @@ -600,17 +669,17 @@ public class NitzStateMachine { } /** * Clear the mNitzUpdatedTime flag. * Clear the mNitzTimeZoneDetectionSuccessful flag. */ public void clearNitzUpdatedTime() { mNitzUpdatedTime = false; public void clearNitzTimeZoneDetectionSuccessful() { mNitzTimeZoneDetectionSuccessful = false; } /** * Get the mNitzUpdatedTime flag value. * Get the mNitzTimeZoneDetectionSuccessful flag value. */ public boolean getNitzUpdatedTime() { return mNitzUpdatedTime; public boolean getNitzTimeZoneDetectionSuccessful() { return mNitzTimeZoneDetectionSuccessful; } /** Loading @@ -621,10 +690,11 @@ public class NitzStateMachine { } /** * Returns true if mNitzUpdatedTime and automatic time zone detection is enabled. * Returns true if !mNitzTimeZoneDetectionSuccessful and automatic time zone detection is * enabled. */ public boolean shouldUpdateTimeZoneUsingCountryCode() { return !mNitzUpdatedTime && mTimeServiceHelper.isTimeZoneDetectionEnabled(); return !mNitzTimeZoneDetectionSuccessful && mTimeServiceHelper.isTimeZoneDetectionEnabled(); } /** Loading @@ -648,5 +718,4 @@ public class NitzStateMachine { public boolean fixTimeZoneCallNeeded() { return mNeedFixZoneAfterNitz; } } src/java/com/android/internal/telephony/ServiceStateTracker.java +9 −8 Original line number Diff line number Diff line Loading @@ -559,7 +559,7 @@ public class ServiceStateTracker extends Handler { mMin = null; mPrlVersion = null; mIsMinInfoReady = false; mNitzState.clearNitzUpdatedTime(); mNitzState.clearNitzTimeZoneDetectionSuccessful(); //cancel any pending pollstate request on voice tech switching cancelPollState(); Loading Loading @@ -2548,7 +2548,7 @@ public class ServiceStateTracker extends Handler { mNewCellLoc.setStateInvalid(); setSignalStrengthDefaultValues(); mNitzState.setNetworkCountryIsoAvailable(false); mNitzState.clearNitzUpdatedTime(); mNitzState.clearNitzTimeZoneDetectionSuccessful(); pollStateDone(); break; Loading @@ -2557,7 +2557,7 @@ public class ServiceStateTracker extends Handler { mNewCellLoc.setStateInvalid(); setSignalStrengthDefaultValues(); mNitzState.setNetworkCountryIsoAvailable(false); mNitzState.clearNitzUpdatedTime(); mNitzState.clearNitzTimeZoneDetectionSuccessful(); // don't poll when device is shutting down or the poll was not modemTrigged // (they sent us new radio data) and current network is not IWLAN if (mDeviceShuttingDown || Loading Loading @@ -2790,11 +2790,12 @@ public class ServiceStateTracker extends Handler { mNetworkAttachedRegistrants.notifyRegistrants(); if (DBG) { log("pollStateDone: hasRegistered, current mNitzState.getNitzUpdatedTime()=" + mNitzState.getNitzUpdatedTime() + ". Calling mNitzState.clearNitzUpdatedTime()"); log("pollStateDone: hasRegistered," + " current mNitzState.getNitzTimeZoneDetectionSuccessful()=" + mNitzState.getNitzTimeZoneDetectionSuccessful() + ". Calling mNitzState.clearNitzTimeZoneDetectionSuccessful()"); } mNitzState.clearNitzUpdatedTime(); mNitzState.clearNitzTimeZoneDetectionSuccessful(); } if (hasDeregistered) { Loading Loading @@ -2828,7 +2829,7 @@ public class ServiceStateTracker extends Handler { if (DBG) log("operatorNumeric " + operatorNumeric + " is invalid"); tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), ""); mNitzState.setNetworkCountryIsoAvailable(false); mNitzState.clearNitzUpdatedTime(); mNitzState.clearNitzTimeZoneDetectionSuccessful(); } else if (mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { // Update time zone, ISO, and IDD. // Loading tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java +8 −0 Original line number Diff line number Diff line Loading @@ -253,6 +253,14 @@ public class ContextFixture implements TestFixture<Context> { } } @Override public String getSystemServiceName(Class<?> serviceClass) { if (serviceClass == SubscriptionManager.class) { return Context.TELEPHONY_SUBSCRIPTION_SERVICE; } return super.getSystemServiceName(serviceClass); } @Override public int getUserId() { return 0; Loading tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTest.java +9 −4 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ public class NitzStateMachineTest extends TelephonyTest { when(mDeviceState.getNitzUpdateDiffMillis()).thenReturn(2000); when(mDeviceState.getNitzUpdateSpacingMillis()).thenReturn(1000 * 60 * 10); when(mDeviceState.elapsedRealtime()).thenReturn(123456789L); when(mDeviceState.currentTimeMillis()).thenReturn(987654321L); mNitzStateMachine = new NitzStateMachine(mPhone, mTimeServiceHelper, mDeviceState); Loading @@ -70,6 +71,7 @@ public class NitzStateMachineTest extends TelephonyTest { verify(mDeviceState, atLeast(0)).getNitzUpdateDiffMillis(); verify(mDeviceState, atLeast(0)).getNitzUpdateSpacingMillis(); verify(mDeviceState, atLeast(0)).elapsedRealtime(); verify(mDeviceState, atLeast(0)).currentTimeMillis(); verify(mDeviceState, atLeast(0)).getNetworkCountryIsoForPhone(); verifyNoMoreInteractions(mDeviceState); Loading Loading @@ -110,7 +112,8 @@ public class NitzStateMachineTest extends TelephonyTest { verifyTimeServiceTimeZoneWasSet(usNitzSignal.getTimeZoneId()); verifyTimeServiceTimeWasSet(expectedAdjustedCurrentTimeMillis); assertTrue(mNitzStateMachine.getNitzUpdatedTime()); assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful()); assertEquals(usNitzSignal.getNitzData(), mNitzStateMachine.getCachedNitzData()); assertEquals(usNitzSignal.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); } Loading Loading @@ -143,7 +146,7 @@ public class NitzStateMachineTest extends TelephonyTest { verifyTimeServiceTimeZoneWasNotSet(); verifyTimeServiceTimeWasSet(expectedAdjustedCurrentTimeMillis); assertTrue(mNitzStateMachine.getNitzUpdatedTime()); assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful()); assertEquals(usNitzSignal.getNitzData(), mNitzStateMachine.getCachedNitzData()); assertEquals(usNitzSignal.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); } Loading Loading @@ -172,7 +175,7 @@ public class NitzStateMachineTest extends TelephonyTest { verifyTimeServiceTimeZoneWasSet(usNitzSignal.getTimeZoneId()); verifyTimeServiceTimeWasNotSet(); assertTrue(mNitzStateMachine.getNitzUpdatedTime()); assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful()); assertEquals(usNitzSignal.getNitzData(), mNitzStateMachine.getCachedNitzData()); assertEquals(usNitzSignal.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); } Loading Loading @@ -201,7 +204,7 @@ public class NitzStateMachineTest extends TelephonyTest { verifyTimeServiceTimeZoneWasNotSet(); verifyTimeServiceTimeWasNotSet(); assertTrue(mNitzStateMachine.getNitzUpdatedTime()); assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful()); assertEquals(usNitzSignal.getNitzData(), mNitzStateMachine.getCachedNitzData()); assertEquals(usNitzSignal.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); } Loading @@ -227,6 +230,8 @@ public class NitzStateMachineTest extends TelephonyTest { private void incrementSimulatedDeviceClock(int incMillis) { long currentElapsedRealtime = mDeviceState.elapsedRealtime(); when(mDeviceState.elapsedRealtime()).thenReturn(currentElapsedRealtime + incMillis); long currentTimeMillis = mDeviceState.currentTimeMillis(); when(mDeviceState.elapsedRealtime()).thenReturn(currentTimeMillis + incMillis); } private static long createTime(TimeZone timeZone, int year, int monthOfYear, int dayOfMonth, Loading Loading
src/java/com/android/internal/telephony/NitzStateMachine.java +176 −107 Original line number Diff line number Diff line Loading @@ -98,6 +98,13 @@ public class NitzStateMachine { return ignoreNitz != null && ignoreNitz.equals("yes"); } /** * Returns the same value as {@link System#currentTimeMillis()}. */ public long currentTimeMillis() { return System.currentTimeMillis(); } /** * Returns the same value as {@link SystemClock#elapsedRealtime()}. */ Loading @@ -110,6 +117,31 @@ public class NitzStateMachine { } } /** A pair containing a value and an associated time stamp. */ private static class TimeStampedValue<T> { /** The value. */ final T mValue; /** * The value of {@link SystemClock#elapsedRealtime} or equivalent when value was * determined. */ final long mElapsedRealtime; TimeStampedValue(T value, long elapsedRealtime) { this.mValue = value; this.mElapsedRealtime = elapsedRealtime; } @Override public String toString() { return "TimeStampedValue{" + "mValue=" + mValue + ", mElapsedRealtime=" + mElapsedRealtime + '}'; } } private static final String LOG_TAG = ServiceStateTracker.LOG_TAG; private static final boolean DBG = ServiceStateTracker.DBG; Loading Loading @@ -142,8 +174,16 @@ public class NitzStateMachine { "tg", // Togo }; private final LocalLog mTimeLog = new LocalLog(15); private final LocalLog mTimeZoneLog = new LocalLog(15); // Time detection state. /** * The last NITZ-sourced time considered. If auto time detection was off at the time this may * not have been used to set the device time, but it can be used if auto time detection is * re-enabled. */ private TimeStampedValue<Long> mSavedNitzTime; // Time Zone detection state. /** * Sometimes we get the NITZ time before we know what country we Loading @@ -155,19 +195,26 @@ public class NitzStateMachine { private NitzData mNitzData; private boolean mGotCountryCode = false; private String mSavedTimeZoneId; private long mSavedTime; private long mSavedAtTime; /** Wake lock used while setting time of day. */ private PowerManager.WakeLock mWakeLock; private static final String WAKELOCK_TAG = "NitzStateMachine"; /** Boolean is true if setTimeFromNITZ was called */ private boolean mNitzUpdatedTime = false; /** * Boolean is {@code true} if {@link #setTimeZoneFromNitz(NitzData, long)} has been called and * was able to determine a time zone (which may not ultimately have been used due to user * settings). Cleared by {@link #clearNitzTimeZoneDetectionSuccessful()}, * The flag can be used when historic NITZ data may no longer be valid. {@code true} indicates * it's not reasonable to try to set the time zone using less reliable algorithms than * NITZ-based detection such as by just using network country code. */ private boolean mNitzTimeZoneDetectionSuccessful = false; // Miscellaneous dependencies and helpers not related to detection state. private final LocalLog mTimeLog = new LocalLog(15); private final LocalLog mTimeZoneLog = new LocalLog(15); private final GsmCdmaPhone mPhone; private final DeviceState mDeviceState; private final TimeServiceHelper mTimeServiceHelper; /** Wake lock used while setting time of day. */ private final PowerManager.WakeLock mWakeLock; private static final String WAKELOCK_TAG = "NitzStateMachine"; public NitzStateMachine(GsmCdmaPhone phone) { this(phone, Loading Loading @@ -251,7 +298,11 @@ public class NitzStateMachine { // a zero UTC offset) the device will retain the existing time zone setting and not try // to derive one from the isoCountryCode. if (mNeedFixZoneAfterNitz) { long ctm = System.currentTimeMillis(); try { // Acquire the wakelock as we're reading the system clock here. mWakeLock.acquire(); long ctm = mDeviceState.currentTimeMillis(); long tzOffset = zone.getOffset(ctm); if (DBG) { Rlog.d(LOG_TAG, "fixTimeZone: tzOffset=" + tzOffset Loading @@ -259,17 +310,19 @@ public class NitzStateMachine { } if (mTimeServiceHelper.isTimeDetectionEnabled()) { long adj = ctm - tzOffset; if (DBG) { Rlog.d(LOG_TAG, "fixTimeZone: adj ltod=" + TimeUtils.logTimeOfDay(adj)); } setAndBroadcastNetworkSetTime(adj); String msg = "fixTimeZone: adj ltod=" + TimeUtils.logTimeOfDay(adj); setAndBroadcastNetworkSetTime(msg, adj); } else { // Adjust the saved NITZ time to account for tzOffset. mSavedTime = mSavedTime - tzOffset; mSavedNitzTime = new TimeStampedValue<>( mSavedNitzTime.mValue - tzOffset, mSavedNitzTime.mElapsedRealtime); if (DBG) { Rlog.d(LOG_TAG, "fixTimeZone: adj mSavedTime=" + mSavedTime); Rlog.d(LOG_TAG, "fixTimeZone: adj mSavedTime=" + mSavedNitzTime); } } } finally { mWakeLock.release(); } } if (DBG) { Rlog.d(LOG_TAG, "fixTimeZone: using default TimeZone"); Loading Loading @@ -327,7 +380,10 @@ public class NitzStateMachine { */ public void setTimeAndTimeZoneFromNitz(NitzData newNitzData, long nitzReceiveTime) { setTimeZoneFromNitz(newNitzData, nitzReceiveTime); setTimeFromNitz(newNitzData, nitzReceiveTime); TimeStampedValue<NitzData> nitzSignal = new TimeStampedValue<>(newNitzData, nitzReceiveTime); setTimeFromNitz(nitzSignal); } private void setTimeZoneFromNitz(NitzData newNitzData, long nitzReceiveTime) { Loading Loading @@ -395,6 +451,7 @@ public class NitzStateMachine { if (mTimeServiceHelper.isTimeZoneDetectionEnabled()) { setAndBroadcastNetworkSetTimeZone(zone.getID()); } mNitzTimeZoneDetectionSuccessful = true; saveNitzTimeZone(zone.getID()); } } catch (RuntimeException ex) { Loading @@ -402,84 +459,84 @@ public class NitzStateMachine { } } private void setTimeFromNitz(NitzData newNitzData, long nitzReceiveTime) { private void setTimeFromNitz(TimeStampedValue<NitzData> nitzTimeSignal) { try { boolean ignoreNitz = mDeviceState.getIgnoreNitz(); if (ignoreNitz) { Rlog.d(LOG_TAG, "NITZ: Not setting clock because gsm.ignore-nitz is set"); Rlog.d(LOG_TAG, "setTimeFromNitz: Not setting clock because gsm.ignore-nitz is set"); return; } try { // Acquire the wake lock as we are reading the elapsed realtime clock and system // clock. mWakeLock.acquire(); long millisSinceNitzReceived = mDeviceState.elapsedRealtime() - nitzReceiveTime; if (millisSinceNitzReceived < 0) { // Sanity check: something is wrong if (DBG) { Rlog.d(LOG_TAG, "NITZ: not setting time, clock has rolled " + "backwards since NITZ time was received, " + newNitzData); } return; } if (millisSinceNitzReceived > Integer.MAX_VALUE) { // If the time is this far off, something is wrong > 24 days! // Validate the nitzTimeSignal to reject obviously bogus elapsedRealtime values. long elapsedRealtime = mDeviceState.elapsedRealtime(); long millisSinceNitzReceived = elapsedRealtime - nitzTimeSignal.mElapsedRealtime; if (millisSinceNitzReceived < 0 || millisSinceNitzReceived > Integer.MAX_VALUE) { if (DBG) { Rlog.d(LOG_TAG, "NITZ: not setting time, processing has taken " + (millisSinceNitzReceived / (1000 * 60 * 60 * 24)) + " days"); Rlog.d(LOG_TAG, "setTimeFromNitz: not setting time, unexpected" + " elapsedRealtime=" + elapsedRealtime + " nitzTimeSignal=" + nitzTimeSignal); } return; } // Adjust the NITZ time by the delay since it was received. long adjustedCurrentTimeMillis = newNitzData.getCurrentTimeInMillis(); adjustedCurrentTimeMillis += millisSinceNitzReceived; // Adjust the NITZ time by the delay since it was received to get the time now. long adjustedCurrentTimeMillis = nitzTimeSignal.mValue.getCurrentTimeInMillis() + millisSinceNitzReceived; long gained = adjustedCurrentTimeMillis - mDeviceState.currentTimeMillis(); if (mTimeServiceHelper.isTimeDetectionEnabled()) { String tmpLog = "NITZ: newNitaData=" + newNitzData + " nitzReceiveTime=" + nitzReceiveTime + " Setting time of day to " + adjustedCurrentTimeMillis + " NITZ receive delay(ms): " + millisSinceNitzReceived + " gained(ms): " + (adjustedCurrentTimeMillis - System.currentTimeMillis()); if (DBG) { Rlog.d(LOG_TAG, tmpLog); } mTimeLog.log(tmpLog); // Update system time automatically long gained = adjustedCurrentTimeMillis - System.currentTimeMillis(); long timeSinceLastUpdate = mDeviceState.elapsedRealtime() - mSavedAtTime; String logMsg = "(setTimeFromNitz)" + " nitzTimeSignal=" + nitzTimeSignal + " adjustedCurrentTimeMillis=" + adjustedCurrentTimeMillis + " millisSinceNitzReceived= " + millisSinceNitzReceived + " gained=" + gained; if (mSavedNitzTime == null) { logMsg += ": First update received."; setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis); } else { long elapsedRealtimeSinceLastSaved = mDeviceState.elapsedRealtime() - mSavedNitzTime.mElapsedRealtime; int nitzUpdateSpacing = mDeviceState.getNitzUpdateSpacingMillis(); int nitzUpdateDiff = mDeviceState.getNitzUpdateDiffMillis(); if ((mSavedAtTime == 0) || (timeSinceLastUpdate > nitzUpdateSpacing) || (Math.abs(gained) > nitzUpdateDiff)) { if (DBG) { Rlog.d(LOG_TAG, "NITZ: Auto updating time of day to " + adjustedCurrentTimeMillis + " NITZ receive delay=" + millisSinceNitzReceived + "ms gained=" + gained + "ms from " + newNitzData); } setAndBroadcastNetworkSetTime(adjustedCurrentTimeMillis); if (elapsedRealtimeSinceLastSaved > nitzUpdateSpacing || Math.abs(gained) > nitzUpdateDiff) { // Either it has been a while since we received an update, or the gain // is sufficiently large that we want to act on it. logMsg += ": New update received."; setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis); } else { if (DBG) { Rlog.d(LOG_TAG, "NITZ: ignore, a previous update was " + timeSinceLastUpdate + "ms ago and gained=" + gained + "ms"); Rlog.d(LOG_TAG, logMsg + ": Update throttled."); } // Return early. This means that we don't reset the // mSavedNitzTime for next time and that we may act on more // NITZ time signals overall but should end up with a system clock that // tracks NITZ more closely than if we saved throttled values (which // would reset mSavedNitzTime.elapsedRealtime used to calculate time // since the last NITZ signal was received). return; } } saveNitzTime(adjustedCurrentTimeMillis); } // Save the last NITZ time signal used so we can return to it later // if auto-time detection is toggled. mSavedNitzTime = new TimeStampedValue<>( adjustedCurrentTimeMillis, nitzTimeSignal.mElapsedRealtime); } finally { mWakeLock.release(); } } catch (RuntimeException ex) { Rlog.e(LOG_TAG, "NITZ: Processing NITZ data " + newNitzData + " ex=" + ex); Rlog.e(LOG_TAG, "setTimeFromNitz: Processing NITZ data " + nitzTimeSignal + " ex=" + ex); } } Loading @@ -487,12 +544,6 @@ public class NitzStateMachine { mSavedTimeZoneId = zoneId; } private void saveNitzTime(long time) { mSavedTime = time; mSavedAtTime = mDeviceState.elapsedRealtime(); mNitzUpdatedTime = true; } private void setAndBroadcastNetworkSetTimeZone(String zoneId) { if (DBG) { Rlog.d(LOG_TAG, "setAndBroadcastNetworkSetTimeZone: setTimeZone=" + zoneId); Loading @@ -505,24 +556,38 @@ public class NitzStateMachine { } } private void setAndBroadcastNetworkSetTime(long time) { private void setAndBroadcastNetworkSetTime(String msg, long time) { if (!mWakeLock.isHeld()) { Rlog.w(LOG_TAG, "Wake lock not held while setting device time (msg=" + msg + ")"); } msg = "setAndBroadcastNetworkSetTime: [setting time to time=" + time + "]:" + msg; if (DBG) { Rlog.d(LOG_TAG, "setAndBroadcastNetworkSetTime: time=" + time + "ms"); Rlog.d(LOG_TAG, msg); } mTimeLog.log(msg); mTimeServiceHelper.setDeviceTime(time); TelephonyMetrics.getInstance().writeNITZEvent(mPhone.getPhoneId(), time); } private void revertToNitzTime() { if (DBG) { Rlog.d(LOG_TAG, "Reverting to NITZ Time: mSavedTime=" + mSavedTime + " mSavedAtTime=" + mSavedAtTime); Rlog.d(LOG_TAG, "Reverting to NITZ Time: mSavedTime=" + mSavedNitzTime); } if (mSavedNitzTime != null) { try { // Acquire the wakelock as we're reading the elapsed realtime clock here. mWakeLock.acquire(); long elapsedRealtime = mDeviceState.elapsedRealtime(); String msg = "Reverting to NITZ time, elapsedRealtime=" + elapsedRealtime + " mSavedNitzTime=" + mSavedNitzTime; long adjustedCurrentTimeMillis = mSavedNitzTime.mValue + (elapsedRealtime - mSavedNitzTime.mElapsedRealtime); setAndBroadcastNetworkSetTime(msg, adjustedCurrentTimeMillis); } finally { mWakeLock.release(); } if (mSavedTime != 0 && mSavedAtTime != 0) { long currTime = mDeviceState.elapsedRealtime(); mTimeLog.log("Reverting to NITZ time, currTime=" + currTime + " mSavedAtTime=" + mSavedAtTime + " mSavedTime=" + mSavedTime); setAndBroadcastNetworkSetTime(mSavedTime + (currTime - mSavedAtTime)); } } Loading @@ -546,14 +611,18 @@ public class NitzStateMachine { * Dumps the current in-memory state to the supplied PrintWriter. */ public void dumpState(PrintWriter pw) { // Time Detection State pw.println(" mSavedTime=" + mSavedNitzTime); // Time Zone Detection State pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz); pw.println(" mNitzData=" + mNitzData); pw.println(" mGotCountryCode=" + mGotCountryCode); pw.println(" mSavedTimeZone=" + mSavedTimeZoneId); pw.println(" mSavedTime=" + mSavedTime); pw.println(" mSavedAtTime=" + mSavedAtTime); pw.println(" mNitzTimeZoneDetectionSuccessful=" + mNitzTimeZoneDetectionSuccessful); // Miscellaneous pw.println(" mWakeLock=" + mWakeLock); pw.println(" mNitzUpdatedTime=" + mNitzUpdatedTime); pw.flush(); } Loading Loading @@ -600,17 +669,17 @@ public class NitzStateMachine { } /** * Clear the mNitzUpdatedTime flag. * Clear the mNitzTimeZoneDetectionSuccessful flag. */ public void clearNitzUpdatedTime() { mNitzUpdatedTime = false; public void clearNitzTimeZoneDetectionSuccessful() { mNitzTimeZoneDetectionSuccessful = false; } /** * Get the mNitzUpdatedTime flag value. * Get the mNitzTimeZoneDetectionSuccessful flag value. */ public boolean getNitzUpdatedTime() { return mNitzUpdatedTime; public boolean getNitzTimeZoneDetectionSuccessful() { return mNitzTimeZoneDetectionSuccessful; } /** Loading @@ -621,10 +690,11 @@ public class NitzStateMachine { } /** * Returns true if mNitzUpdatedTime and automatic time zone detection is enabled. * Returns true if !mNitzTimeZoneDetectionSuccessful and automatic time zone detection is * enabled. */ public boolean shouldUpdateTimeZoneUsingCountryCode() { return !mNitzUpdatedTime && mTimeServiceHelper.isTimeZoneDetectionEnabled(); return !mNitzTimeZoneDetectionSuccessful && mTimeServiceHelper.isTimeZoneDetectionEnabled(); } /** Loading @@ -648,5 +718,4 @@ public class NitzStateMachine { public boolean fixTimeZoneCallNeeded() { return mNeedFixZoneAfterNitz; } }
src/java/com/android/internal/telephony/ServiceStateTracker.java +9 −8 Original line number Diff line number Diff line Loading @@ -559,7 +559,7 @@ public class ServiceStateTracker extends Handler { mMin = null; mPrlVersion = null; mIsMinInfoReady = false; mNitzState.clearNitzUpdatedTime(); mNitzState.clearNitzTimeZoneDetectionSuccessful(); //cancel any pending pollstate request on voice tech switching cancelPollState(); Loading Loading @@ -2548,7 +2548,7 @@ public class ServiceStateTracker extends Handler { mNewCellLoc.setStateInvalid(); setSignalStrengthDefaultValues(); mNitzState.setNetworkCountryIsoAvailable(false); mNitzState.clearNitzUpdatedTime(); mNitzState.clearNitzTimeZoneDetectionSuccessful(); pollStateDone(); break; Loading @@ -2557,7 +2557,7 @@ public class ServiceStateTracker extends Handler { mNewCellLoc.setStateInvalid(); setSignalStrengthDefaultValues(); mNitzState.setNetworkCountryIsoAvailable(false); mNitzState.clearNitzUpdatedTime(); mNitzState.clearNitzTimeZoneDetectionSuccessful(); // don't poll when device is shutting down or the poll was not modemTrigged // (they sent us new radio data) and current network is not IWLAN if (mDeviceShuttingDown || Loading Loading @@ -2790,11 +2790,12 @@ public class ServiceStateTracker extends Handler { mNetworkAttachedRegistrants.notifyRegistrants(); if (DBG) { log("pollStateDone: hasRegistered, current mNitzState.getNitzUpdatedTime()=" + mNitzState.getNitzUpdatedTime() + ". Calling mNitzState.clearNitzUpdatedTime()"); log("pollStateDone: hasRegistered," + " current mNitzState.getNitzTimeZoneDetectionSuccessful()=" + mNitzState.getNitzTimeZoneDetectionSuccessful() + ". Calling mNitzState.clearNitzTimeZoneDetectionSuccessful()"); } mNitzState.clearNitzUpdatedTime(); mNitzState.clearNitzTimeZoneDetectionSuccessful(); } if (hasDeregistered) { Loading Loading @@ -2828,7 +2829,7 @@ public class ServiceStateTracker extends Handler { if (DBG) log("operatorNumeric " + operatorNumeric + " is invalid"); tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), ""); mNitzState.setNetworkCountryIsoAvailable(false); mNitzState.clearNitzUpdatedTime(); mNitzState.clearNitzTimeZoneDetectionSuccessful(); } else if (mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { // Update time zone, ISO, and IDD. // Loading
tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java +8 −0 Original line number Diff line number Diff line Loading @@ -253,6 +253,14 @@ public class ContextFixture implements TestFixture<Context> { } } @Override public String getSystemServiceName(Class<?> serviceClass) { if (serviceClass == SubscriptionManager.class) { return Context.TELEPHONY_SUBSCRIPTION_SERVICE; } return super.getSystemServiceName(serviceClass); } @Override public int getUserId() { return 0; Loading
tests/telephonytests/src/com/android/internal/telephony/NitzStateMachineTest.java +9 −4 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ public class NitzStateMachineTest extends TelephonyTest { when(mDeviceState.getNitzUpdateDiffMillis()).thenReturn(2000); when(mDeviceState.getNitzUpdateSpacingMillis()).thenReturn(1000 * 60 * 10); when(mDeviceState.elapsedRealtime()).thenReturn(123456789L); when(mDeviceState.currentTimeMillis()).thenReturn(987654321L); mNitzStateMachine = new NitzStateMachine(mPhone, mTimeServiceHelper, mDeviceState); Loading @@ -70,6 +71,7 @@ public class NitzStateMachineTest extends TelephonyTest { verify(mDeviceState, atLeast(0)).getNitzUpdateDiffMillis(); verify(mDeviceState, atLeast(0)).getNitzUpdateSpacingMillis(); verify(mDeviceState, atLeast(0)).elapsedRealtime(); verify(mDeviceState, atLeast(0)).currentTimeMillis(); verify(mDeviceState, atLeast(0)).getNetworkCountryIsoForPhone(); verifyNoMoreInteractions(mDeviceState); Loading Loading @@ -110,7 +112,8 @@ public class NitzStateMachineTest extends TelephonyTest { verifyTimeServiceTimeZoneWasSet(usNitzSignal.getTimeZoneId()); verifyTimeServiceTimeWasSet(expectedAdjustedCurrentTimeMillis); assertTrue(mNitzStateMachine.getNitzUpdatedTime()); assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful()); assertEquals(usNitzSignal.getNitzData(), mNitzStateMachine.getCachedNitzData()); assertEquals(usNitzSignal.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); } Loading Loading @@ -143,7 +146,7 @@ public class NitzStateMachineTest extends TelephonyTest { verifyTimeServiceTimeZoneWasNotSet(); verifyTimeServiceTimeWasSet(expectedAdjustedCurrentTimeMillis); assertTrue(mNitzStateMachine.getNitzUpdatedTime()); assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful()); assertEquals(usNitzSignal.getNitzData(), mNitzStateMachine.getCachedNitzData()); assertEquals(usNitzSignal.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); } Loading Loading @@ -172,7 +175,7 @@ public class NitzStateMachineTest extends TelephonyTest { verifyTimeServiceTimeZoneWasSet(usNitzSignal.getTimeZoneId()); verifyTimeServiceTimeWasNotSet(); assertTrue(mNitzStateMachine.getNitzUpdatedTime()); assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful()); assertEquals(usNitzSignal.getNitzData(), mNitzStateMachine.getCachedNitzData()); assertEquals(usNitzSignal.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); } Loading Loading @@ -201,7 +204,7 @@ public class NitzStateMachineTest extends TelephonyTest { verifyTimeServiceTimeZoneWasNotSet(); verifyTimeServiceTimeWasNotSet(); assertTrue(mNitzStateMachine.getNitzUpdatedTime()); assertTrue(mNitzStateMachine.getNitzTimeZoneDetectionSuccessful()); assertEquals(usNitzSignal.getNitzData(), mNitzStateMachine.getCachedNitzData()); assertEquals(usNitzSignal.getTimeZoneId(), mNitzStateMachine.getSavedTimeZoneId()); } Loading @@ -227,6 +230,8 @@ public class NitzStateMachineTest extends TelephonyTest { private void incrementSimulatedDeviceClock(int incMillis) { long currentElapsedRealtime = mDeviceState.elapsedRealtime(); when(mDeviceState.elapsedRealtime()).thenReturn(currentElapsedRealtime + incMillis); long currentTimeMillis = mDeviceState.currentTimeMillis(); when(mDeviceState.elapsedRealtime()).thenReturn(currentTimeMillis + incMillis); } private static long createTime(TimeZone timeZone, int year, int monthOfYear, int dayOfMonth, Loading