Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb8be938 authored by Neil Fuller's avatar Neil Fuller
Browse files

Make state transitions clearer in NitzStateMachine

All state transitions are triggered in "handleXyz"
methods and ServiceStateTracker calls them at obvious
places.

Some of the logic when the MCC becomes known has been
pulled together into a single method from several
separate calls. This change may introduce some
functional changes as a result of these changes.
A field has been renamed to try to make the logic
still clearer now the state is not inspected by
ServiceStateTracker.

An additional call has been added to
handleNetworkUnavailable() in a place where it seems
appropriate.

The interface between ServiceStateTracker and
NitzStateMachine should be stable at this point,
allowing for NitzStateMachine to become an abstract
or interface class and enable an alternative
implementation to be swapped in.

Test: atest FrameworksTelephonyTests
Bug: 63743683
Change-Id: I2e03f9bbce06e2a03b32e467deb2a0a269adecb8
parent a0f09cee
Loading
Loading
Loading
Loading
+165 −153
Original line number Diff line number Diff line
@@ -135,19 +135,20 @@ public class NitzStateMachine {
     * are in. Keep the time zone information from the NITZ string in
     * mNitzData so we can fix the time zone once know the country.
     */
    private boolean mNeedFixZoneAfterNitz = false;
    private boolean mNeedCountryCodeForNitz = false;

    private NitzData mNitzData;
    private boolean mGotCountryCode = false;
    private String mSavedTimeZoneId;

    /**
     * Boolean is {@code true} if {@link #setTimeZoneFromNitz(NitzData, long)} has been called and
     * Boolean is {@code true} if {@link #handleNitzReceived(TimeStampedValue)} 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.
     * settings). Cleared by {@link #handleNetworkAvailable()} and
     * {@link #handleNetworkUnavailable()}. 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;

@@ -186,27 +187,41 @@ public class NitzStateMachine {
            @Override
            public void onTimeDetectionChange(boolean enabled) {
                if (enabled) {
                    revertToNitzTime();
                    handleAutoTimeEnabled();
                }
            }

            @Override
            public void onTimeZoneDetectionChange(boolean enabled) {
                if (enabled) {
                    revertToNitzTimeZone();
                    handleAutoTimeZoneEnabled();
                }
            }
        });
    }

    /**
     * Called when the device's network country is known, allowing the time zone detection to be
     * substantially more precise.
     * Called when the network country is set on the Phone. Although set, the network country code
     * may be invalid.
     *
     * @param countryChanged true when the country code is known to have changed, false if it
     *     probably hasn't
     */
    public void fixTimeZone(String isoCountryCode) {
        // Capture the time zone property. This allows us to tell whether the device has a time zone
        // set. TimeZone.getDefault() returns a default zone (GMT) even when time zone is not
        // explicitly set making the system property a better indicator.
    public void handleNetworkCountryCodeSet(boolean countryChanged) {
        mGotCountryCode = true;

        String isoCountryCode = mDeviceState.getNetworkCountryIsoForPhone();
        if (!TextUtils.isEmpty(isoCountryCode)
                && !mNitzTimeZoneDetectionSuccessful
                && mTimeServiceHelper.isTimeZoneDetectionEnabled()) {
            updateTimeZoneByNetworkCountryCode(isoCountryCode);
        }

        if (countryChanged || mNeedCountryCodeForNitz) {
            // Capture the time zone property. This allows us to tell whether the device has a time
            // zone set. TimeZone.getDefault() returns a default zone (GMT) even when time zone is
            // not explicitly set making the system property a better indicator of whether an
            // explicit time zone choice has been made.
            final boolean isTimeZoneSettingInitialized =
                    mTimeServiceHelper.isTimeZoneSettingInitialized();
            if (DBG) {
@@ -214,15 +229,16 @@ public class NitzStateMachine {
                        + " isTimeZoneSettingInitialized=" + isTimeZoneSettingInitialized
                        + " mNitzData=" + mNitzData
                        + " iso-cc='" + isoCountryCode
                    + "' countryUsesUtc=" + mTimeZoneLookupHelper.countryUsesUtc(isoCountryCode));
                        + "' countryUsesUtc="
                        + mTimeZoneLookupHelper.countryUsesUtc(isoCountryCode));
            }
            String zoneId;
        if ("".equals(isoCountryCode) && mNeedFixZoneAfterNitz) {
            if (TextUtils.isEmpty(isoCountryCode) && mNeedCountryCodeForNitz) {
                // Country code not found.  This is likely a test network.
                // Get a TimeZone based only on the NITZ parameters (best guess).

            // mNeedFixZoneAfterNitz is only set to true when mNitzData is set so there's no need to
            // check mNitzData == null.
                // mNeedCountryCodeForNitz is only set to true when mNitzData is set so there's no
                // need to check mNitzData == null.
                zoneId = mTimeZoneLookupHelper.guessZoneIdByNitz(mNitzData);
                if (DBG) {
                    Rlog.d(LOG_TAG, "fixTimeZone(): guessNitzTimeZone returned " + zoneId);
@@ -231,21 +247,22 @@ public class NitzStateMachine {
                    && isTimeZoneSettingInitialized
                    && !mTimeZoneLookupHelper.countryUsesUtc(isoCountryCode)) {

            // This case means that (1) the device received no NITZ signal yet or received an NITZ
            // signal that looks bogus due to having a zero offset from UTC, (2) the device has a
            // time zone set explicitly, and (3) the iso tells us the country is NOT one that uses a
            // zero offset. This is interpreted as being NITZ incorrectly reporting a local time and
            // not a UTC time. The zone is left as the current device's zone setting, and the time
            // may be adjusted by assuming the current zone setting is correct.
                // This case means that (1) the device received no NITZ signal yet or received an
                // NITZ signal that looks bogus due to having a zero offset from UTC, (2) the device
                // has a time zone set explicitly, and (3) the iso tells us the country is NOT one
                // that uses a zero offset. This is interpreted as being NITZ incorrectly reporting
                // a local time and not a UTC time. The zone is left as the current device's zone
                // setting, and the time may be adjusted by assuming the current zone setting is
                // correct.
                TimeZone zone = TimeZone.getDefault();
                zoneId = zone.getID();

            // Note that mNeedFixZoneAfterNitz => (implies) { mNitzData != null }. Therefore, if
            // mNitzData == null, mNeedFixZoneAfterNitz cannot be true. The code in this section
            // therefore means that when mNitzData == null (and the country is one that doesn't use
            // a zero UTC offset) the device will retain the existing time zone setting and not try
            // to derive one from the isoCountryCode.
            if (mNeedFixZoneAfterNitz) {
                // Note that mNeedCountryCodeForNitz => (implies) { mNitzData != null }. Therefore,
                // if mNitzData == null, mNeedCountryCodeForNitz cannot be true. The code in this
                // section therefore means that when mNitzData == null (and the country is one that
                // doesn't use a zero UTC offset) the device will retain the existing time zone
                // setting and not try to derive one from the isoCountryCode.
                if (mNeedCountryCodeForNitz) {
                    try {
                        // Acquire the wakelock as we're reading the system clock here.
                        mWakeLock.acquire();
@@ -263,7 +280,8 @@ public class NitzStateMachine {
                        } else {
                            // Adjust the saved NITZ time to account for tzOffset.
                            mSavedNitzTime = new TimeStampedValue<>(
                                mSavedNitzTime.mValue - tzOffset, mSavedNitzTime.mElapsedRealtime);
                                    mSavedNitzTime.mValue - tzOffset,
                                    mSavedNitzTime.mElapsedRealtime);
                            if (DBG) {
                                Rlog.d(LOG_TAG, "fixTimeZone: adj mSavedTime=" + mSavedNitzTime);
                            }
@@ -282,7 +300,7 @@ public class NitzStateMachine {
                        0 /* when */, 0 /* offset */, false /* dst */, isoCountryCode);
                if (DBG) {
                    Rlog.d(LOG_TAG, "fixTimeZone: No cached NITZ data available, using only country"
                        + " code. zone=" + zoneId);
                            + " code. zoneId=" + zoneId);
                }
            } else {
                zoneId = mTimeZoneLookupHelper.guessZoneIdByNitzCountry(mNitzData, isoCountryCode);
@@ -294,7 +312,7 @@ public class NitzStateMachine {
                    + " isTimeZoneSettingInitialized=" + isTimeZoneSettingInitialized
                    + " mNitzData=" + mNitzData
                    + " iso-cc=" + isoCountryCode
                + " mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz
                    + " mNeedCountryCodeForNitz=" + mNeedCountryCodeForNitz
                    + " zoneId=" + zoneId;
            mTimeZoneLog.log(tmpLog);

@@ -305,13 +323,38 @@ public class NitzStateMachine {
                } else {
                    Rlog.d(LOG_TAG, "fixTimeZone: skip changing zone as getAutoTimeZone was false");
                }
            if (mNeedFixZoneAfterNitz) {
                if (mNeedCountryCodeForNitz) {
                    saveNitzTimeZone(zoneId);
                }
            } else {
                Rlog.d(LOG_TAG, "fixTimeZone: zone == null, do nothing for zone");
            }
        mNeedFixZoneAfterNitz = false;
            mNeedCountryCodeForNitz = false;
        }
    }

    /**
     * Informs the {@link NitzStateMachine} that the network has become available.
     */
    public void handleNetworkAvailable() {
        if (DBG) {
            Rlog.d(LOG_TAG, "handleNetworkAvailable: mNitzTimeZoneDetectionSuccessful="
                    + mNitzTimeZoneDetectionSuccessful
                    + ", Setting mNitzTimeZoneDetectionSuccessful=false");
        }
        mNitzTimeZoneDetectionSuccessful = false;
    }

    /**
     * Informs the {@link NitzStateMachine} that the network has become unavailable.
     */
    public void handleNetworkUnavailable() {
        if (DBG) {
            Rlog.d(LOG_TAG, "handleNetworkUnavailable");
        }

        mGotCountryCode = false;
        mNitzTimeZoneDetectionSuccessful = false;
    }

    /**
@@ -325,16 +368,14 @@ public class NitzStateMachine {
    /**
     * Handle a new NITZ signal being received.
     */
    public void setTimeAndTimeZoneFromNitz(NitzData newNitzData, long nitzReceiveTime) {
        setTimeZoneFromNitz(newNitzData, nitzReceiveTime);

        TimeStampedValue<NitzData> nitzSignal =
                new TimeStampedValue<>(newNitzData, nitzReceiveTime);
        setTimeFromNitz(nitzSignal);
    public void handleNitzReceived(TimeStampedValue<NitzData> nitzSignal) {
        handleTimeZoneFromNitz(nitzSignal);
        handleTimeFromNitz(nitzSignal);
    }

    private void setTimeZoneFromNitz(NitzData newNitzData, long nitzReceiveTime) {
    private void handleTimeZoneFromNitz(TimeStampedValue<NitzData> nitzSignal) {
        try {
            NitzData newNitzData = nitzSignal.mValue;
            String iso = mDeviceState.getNetworkCountryIsoForPhone();
            String zoneId;
            if (newNitzData.getEmulatorHostTimeZone() != null) {
@@ -342,7 +383,7 @@ public class NitzStateMachine {
            } else {
                if (!mGotCountryCode) {
                    zoneId = null;
                } else if (iso != null && iso.length() > 0) {
                } else if (!TextUtils.isEmpty(iso)) {
                    zoneId = mTimeZoneLookupHelper.guessZoneIdByNitzCountry(newNitzData, iso);
                } else {
                    // We don't have a valid iso country code.  This is
@@ -373,15 +414,14 @@ public class NitzStateMachine {
                // We got the time before the country or the zone has changed
                // so we don't know how to identify the DST rules yet.  Save
                // the information and hope to fix it up later.
                mNeedFixZoneAfterNitz = true;
                mNeedCountryCodeForNitz = true;
                mNitzData = newNitzData;
            }

            String tmpLog = "NITZ: newNitzData=" + newNitzData
                    + " nitzReceiveTime=" + nitzReceiveTime
            String tmpLog = "NITZ: nitzTimeSignal=" + nitzSignal
                    + " zoneId=" + zoneId
                    + " iso=" + iso + " mGotCountryCode=" + mGotCountryCode
                    + " mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz
                    + " mNeedCountryCodeForNitz=" + mNeedCountryCodeForNitz
                    + " isTimeZoneDetectionEnabled()="
                    + mTimeServiceHelper.isTimeZoneDetectionEnabled();
            if (DBG) {
@@ -397,11 +437,11 @@ public class NitzStateMachine {
                saveNitzTimeZone(zoneId);
            }
        } catch (RuntimeException ex) {
            Rlog.e(LOG_TAG, "NITZ: Processing NITZ data " + newNitzData + " ex=" + ex);
            Rlog.e(LOG_TAG, "NITZ: Processing NITZ data " + nitzSignal + " ex=" + ex);
        }
    }

    private void setTimeFromNitz(TimeStampedValue<NitzData> nitzTimeSignal) {
    private void handleTimeFromNitz(TimeStampedValue<NitzData> nitzTimeSignal) {
        try {
            boolean ignoreNitz = mDeviceState.getIgnoreNitz();
            if (ignoreNitz) {
@@ -512,7 +552,7 @@ public class NitzStateMachine {
        TelephonyMetrics.getInstance().writeNITZEvent(mPhone.getPhoneId(), time);
    }

    private void revertToNitzTime() {
    private void handleAutoTimeEnabled() {
        if (DBG) {
            Rlog.d(LOG_TAG, "Reverting to NITZ Time: mSavedTime=" + mSavedNitzTime);
        }
@@ -533,7 +573,7 @@ public class NitzStateMachine {
        }
    }

    private void revertToNitzTimeZone() {
    private void handleAutoTimeZoneEnabled() {
        String tmpLog = "Reverting to NITZ TimeZone: tz=" + mSavedTimeZoneId;
        if (DBG) {
            Rlog.d(LOG_TAG, tmpLog);
@@ -557,7 +597,7 @@ public class NitzStateMachine {
        pw.println(" mSavedTime=" + mSavedNitzTime);

        // Time Zone Detection State
        pw.println(" mNeedFixZoneAfterNitz=" + mNeedFixZoneAfterNitz);
        pw.println(" mNeedCountryCodeForNitz=" + mNeedCountryCodeForNitz);
        pw.println(" mNitzData=" + mNitzData);
        pw.println(" mGotCountryCode=" + mGotCountryCode);
        pw.println(" mSavedTimeZone=" + mSavedTimeZoneId);
@@ -589,7 +629,7 @@ public class NitzStateMachine {
     *
     * @param iso Country code from network MCC
     */
    public void updateTimeZoneByNetworkCountryCode(String iso) {
    private void updateTimeZoneByNetworkCountryCode(String iso) {
        String zoneId = mTimeZoneLookupHelper.guessZoneIdByCountry(
                iso, mDeviceState.currentTimeMillis());
        if (zoneId != null) {
@@ -610,13 +650,6 @@ public class NitzStateMachine {
        }
    }

    /**
     * Clear the mNitzTimeZoneDetectionSuccessful flag.
     */
    public void clearNitzTimeZoneDetectionSuccessful() {
        mNitzTimeZoneDetectionSuccessful = false;
    }

    /**
     * Get the mNitzTimeZoneDetectionSuccessful flag value.
     */
@@ -624,21 +657,6 @@ public class NitzStateMachine {
        return mNitzTimeZoneDetectionSuccessful;
    }

    /**
     * Sets the mGotCountryCode flag to the specified value.
     */
    public void setNetworkCountryIsoAvailable(boolean gotCountryCode) {
        mGotCountryCode = gotCountryCode;
    }

    /**
     * Returns true if !mNitzTimeZoneDetectionSuccessful and automatic time zone detection is
     * enabled.
     */
    public boolean shouldUpdateTimeZoneUsingCountryCode() {
        return !mNitzTimeZoneDetectionSuccessful && mTimeServiceHelper.isTimeZoneDetectionEnabled();
    }

    /**
     * Returns the last NITZ data that was cached.
     */
@@ -654,10 +672,4 @@ public class NitzStateMachine {
        return mSavedTimeZoneId;
    }

    /**
     * Returns the mNeedFixZoneAfterNitz flag value.
     */
    public boolean fixTimeZoneCallNeeded() {
        return mNeedFixZoneAfterNitz;
    }
}
+56 −74

File changed.

Preview size limit exceeded, changes collapsed.

+38 −46

File changed.

Preview size limit exceeded, changes collapsed.

+12 −3
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.os.Message;
import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.support.test.filters.FlakyTest;
@@ -63,6 +64,7 @@ import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.test.SimulatedCommands;
import com.android.internal.telephony.uicc.IccCardApplicationStatus;
import com.android.internal.telephony.util.TimeStampedValue;

import org.junit.After;
import org.junit.Before;
@@ -1146,8 +1148,7 @@ public class ServiceStateTrackerTest extends TelephonyTest {
            // Mock sending incorrect nitz str from RIL
            mSimulatedCommands.triggerNITZupdate("38/06/20,00:00:00+0");
            waitForMs(200);
            verify(mNitzStateMachine, times(0))
                    .setTimeAndTimeZoneFromNitz(any(), anyLong());
            verify(mNitzStateMachine, times(0)).handleNitzReceived(any());
        }
        {
            // Mock sending correct nitz str from RIL
@@ -1155,8 +1156,16 @@ public class ServiceStateTrackerTest extends TelephonyTest {
            NitzData expectedNitzData = NitzData.parse(nitzStr);
            mSimulatedCommands.triggerNITZupdate(nitzStr);
            waitForMs(200);

            ArgumentCaptor<TimeStampedValue<NitzData>> argumentsCaptor =
                    ArgumentCaptor.forClass(TimeStampedValue.class);
            verify(mNitzStateMachine, times(1))
                    .setTimeAndTimeZoneFromNitz(eq(expectedNitzData), anyLong());
                    .handleNitzReceived(argumentsCaptor.capture());

            // Confirm the argument was what we expected.
            TimeStampedValue<NitzData> actualNitzSignal = argumentsCaptor.getValue();
            assertEquals(expectedNitzData, actualNitzSignal.mValue);
            assertTrue(actualNitzSignal.mElapsedRealtime <= SystemClock.elapsedRealtime());
        }
    }
}