Loading src/java/com/android/internal/telephony/NitzData.java +24 −11 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PACK import com.android.internal.annotations.VisibleForTesting; import com.android.telephony.Rlog; import java.time.DateTimeException; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Objects; Loading @@ -39,9 +40,6 @@ public final class NitzData { private static final int MS_PER_QUARTER_HOUR = 15 * 60 * 1000; private static final int MS_PER_HOUR = 60 * 60 * 1000; /* Time stamp after 19 January 2038 is not supported under 32 bit */ private static final int MAX_NITZ_YEAR = 2037; private static final Pattern NITZ_SPLIT_PATTERN = Pattern.compile("[/:,+-]"); // Stored For logging / debugging only. Loading Loading @@ -77,22 +75,37 @@ public final class NitzData { try { String[] nitzSubs = NITZ_SPLIT_PATTERN.split(nitz); int year = 2000 + Integer.parseInt(nitzSubs[0]); if (year > MAX_NITZ_YEAR) { if (ServiceStateTracker.DBG) { Rlog.e(LOG_TAG, "NITZ year: " + year + " exceeds limit, skip NITZ time update"); } return null; int year = Integer.parseInt(nitzSubs[0]); if (year < 1 || year > 99) { // 0 > year > 99 imply an invalid string. // // At the time of this comment (year 2023), a zero year is considered invalid and // assumed to be the result of invalid data being converted to zero in the code that // turns the binary NITZ into a string. For the next few decades at least, Android // devices should not need to interpret zero. Hopefully, NITZ will be replaced by // the time that's not true, or folks dealing the Y2K1 issue can handle it. // // DateTimeException is also thrown by LocalDateTime below if the values are out of // range and will be handled in the catch block. throw new DateTimeException("Invalid NITZ year == 0"); } // Values < {current year} could be considered invalid but are used in test code, so no // window is applied to adjust low values < {current year} with "+ 2100" (and would also // need to consider zero as valid). Code that processes the NitzData is in a better // position to log and discard obviously invalid NITZ signals from past years. year += 2000; int month = Integer.parseInt(nitzSubs[1]); int date = Integer.parseInt(nitzSubs[2]); int hour = Integer.parseInt(nitzSubs[3]); int minute = Integer.parseInt(nitzSubs[4]); int second = Integer.parseInt(nitzSubs[5]); /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone * offset as well (which we won't worry about until later) */ // NITZ time (hour:min:sec) will be in UTC but it supplies the timezone // offset as well (which we won't worry about until later). // The LocalDateTime.of() will throw DateTimeException for values outside the allowed // range for the Gregorian calendar. long epochMillis = LocalDateTime.of(year, month, date, hour, minute, second) .toInstant(ZoneOffset.UTC) .toEpochMilli(); Loading tests/telephonytests/src/com/android/internal/telephony/NitzDataTest.java +12 −3 Original line number Diff line number Diff line Loading @@ -29,8 +29,17 @@ import java.util.concurrent.TimeUnit; public class NitzDataTest { @Test public void testParse_dateOutsideAllowedRange() { assertNull(NitzData.parse("38/06/20,00:00:00+0")); public void testParse_invalidYear() { assertNull(NitzData.parse("00/06/20,00:00:00+0,0")); } @Test public void testParse_beyond2038() { NitzData nitz = NitzData.parse("40/06/20,01:02:03+4,1"); assertEquals(createUnixEpochTime(2040, 6, 20, 1, 2, 3), nitz.getCurrentTimeInMillis()); assertEquals(TimeUnit.MINUTES.toMillis(4 * 15), nitz.getLocalOffsetMillis()); assertEquals(TimeUnit.MINUTES.toMillis(60), nitz.getDstAdjustmentMillis().longValue()); assertNull(nitz.getEmulatorHostTimeZone()); } @Test Loading @@ -38,7 +47,7 @@ public class NitzDataTest { // "yy/mm/dd,hh:mm:ss(+/-)tz[,dt[,tzid]]" // No tz field. assertNull(NitzData.parse("38/06/20,00:00:00")); assertNull(NitzData.parse("22/06/20,00:00:00")); } @Test Loading tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +0 −13 Original line number Diff line number Diff line Loading @@ -1813,12 +1813,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @SmallTest public void testSetTimeFromNITZStr_withoutAge() throws Exception { { // Mock sending incorrect nitz str from RIL mSimulatedCommands.triggerNITZupdate("38/06/20,00:00:00+0"); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); verify(mNitzStateMachine, times(0)).handleNitzReceived(any()); } { // Mock sending correct nitz str from RIL with a zero ageMs String nitzStr = "15/06/20,00:00:00+0"; Loading @@ -1843,13 +1837,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @SmallTest public void testSetTimeFromNITZStr_withAge() throws Exception { { // Mock sending incorrect nitz str from RIL with a non-zero ageMs long ageMs = 60 * 1000; mSimulatedCommands.triggerNITZupdate("38/06/20,00:00:00+0", ageMs); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); verify(mNitzStateMachine, times(0)).handleNitzReceived(any()); } { // Mock sending correct nitz str from RIL with a non-zero ageMs String nitzStr = "21/08/15,00:00:00+0"; Loading Loading
src/java/com/android/internal/telephony/NitzData.java +24 −11 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PACK import com.android.internal.annotations.VisibleForTesting; import com.android.telephony.Rlog; import java.time.DateTimeException; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Objects; Loading @@ -39,9 +40,6 @@ public final class NitzData { private static final int MS_PER_QUARTER_HOUR = 15 * 60 * 1000; private static final int MS_PER_HOUR = 60 * 60 * 1000; /* Time stamp after 19 January 2038 is not supported under 32 bit */ private static final int MAX_NITZ_YEAR = 2037; private static final Pattern NITZ_SPLIT_PATTERN = Pattern.compile("[/:,+-]"); // Stored For logging / debugging only. Loading Loading @@ -77,22 +75,37 @@ public final class NitzData { try { String[] nitzSubs = NITZ_SPLIT_PATTERN.split(nitz); int year = 2000 + Integer.parseInt(nitzSubs[0]); if (year > MAX_NITZ_YEAR) { if (ServiceStateTracker.DBG) { Rlog.e(LOG_TAG, "NITZ year: " + year + " exceeds limit, skip NITZ time update"); } return null; int year = Integer.parseInt(nitzSubs[0]); if (year < 1 || year > 99) { // 0 > year > 99 imply an invalid string. // // At the time of this comment (year 2023), a zero year is considered invalid and // assumed to be the result of invalid data being converted to zero in the code that // turns the binary NITZ into a string. For the next few decades at least, Android // devices should not need to interpret zero. Hopefully, NITZ will be replaced by // the time that's not true, or folks dealing the Y2K1 issue can handle it. // // DateTimeException is also thrown by LocalDateTime below if the values are out of // range and will be handled in the catch block. throw new DateTimeException("Invalid NITZ year == 0"); } // Values < {current year} could be considered invalid but are used in test code, so no // window is applied to adjust low values < {current year} with "+ 2100" (and would also // need to consider zero as valid). Code that processes the NitzData is in a better // position to log and discard obviously invalid NITZ signals from past years. year += 2000; int month = Integer.parseInt(nitzSubs[1]); int date = Integer.parseInt(nitzSubs[2]); int hour = Integer.parseInt(nitzSubs[3]); int minute = Integer.parseInt(nitzSubs[4]); int second = Integer.parseInt(nitzSubs[5]); /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone * offset as well (which we won't worry about until later) */ // NITZ time (hour:min:sec) will be in UTC but it supplies the timezone // offset as well (which we won't worry about until later). // The LocalDateTime.of() will throw DateTimeException for values outside the allowed // range for the Gregorian calendar. long epochMillis = LocalDateTime.of(year, month, date, hour, minute, second) .toInstant(ZoneOffset.UTC) .toEpochMilli(); Loading
tests/telephonytests/src/com/android/internal/telephony/NitzDataTest.java +12 −3 Original line number Diff line number Diff line Loading @@ -29,8 +29,17 @@ import java.util.concurrent.TimeUnit; public class NitzDataTest { @Test public void testParse_dateOutsideAllowedRange() { assertNull(NitzData.parse("38/06/20,00:00:00+0")); public void testParse_invalidYear() { assertNull(NitzData.parse("00/06/20,00:00:00+0,0")); } @Test public void testParse_beyond2038() { NitzData nitz = NitzData.parse("40/06/20,01:02:03+4,1"); assertEquals(createUnixEpochTime(2040, 6, 20, 1, 2, 3), nitz.getCurrentTimeInMillis()); assertEquals(TimeUnit.MINUTES.toMillis(4 * 15), nitz.getLocalOffsetMillis()); assertEquals(TimeUnit.MINUTES.toMillis(60), nitz.getDstAdjustmentMillis().longValue()); assertNull(nitz.getEmulatorHostTimeZone()); } @Test Loading @@ -38,7 +47,7 @@ public class NitzDataTest { // "yy/mm/dd,hh:mm:ss(+/-)tz[,dt[,tzid]]" // No tz field. assertNull(NitzData.parse("38/06/20,00:00:00")); assertNull(NitzData.parse("22/06/20,00:00:00")); } @Test Loading
tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +0 −13 Original line number Diff line number Diff line Loading @@ -1813,12 +1813,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @SmallTest public void testSetTimeFromNITZStr_withoutAge() throws Exception { { // Mock sending incorrect nitz str from RIL mSimulatedCommands.triggerNITZupdate("38/06/20,00:00:00+0"); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); verify(mNitzStateMachine, times(0)).handleNitzReceived(any()); } { // Mock sending correct nitz str from RIL with a zero ageMs String nitzStr = "15/06/20,00:00:00+0"; Loading @@ -1843,13 +1837,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @SmallTest public void testSetTimeFromNITZStr_withAge() throws Exception { { // Mock sending incorrect nitz str from RIL with a non-zero ageMs long ageMs = 60 * 1000; mSimulatedCommands.triggerNITZupdate("38/06/20,00:00:00+0", ageMs); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); verify(mNitzStateMachine, times(0)).handleNitzReceived(any()); } { // Mock sending correct nitz str from RIL with a non-zero ageMs String nitzStr = "21/08/15,00:00:00+0"; Loading