AlarmManager: Store the next dst transition in system properties

For our current timezone, store the new dst transition properties which are both the Unix epoch time of the next dst transition and the offset in the time during that transition.

Bug: 277283353
Test: Device test, properties are stored as expected
Change-Id: I76b49b816cee24eaabb61c63ee14c9421f631a20
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 39de0af..8258a6f 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -179,6 +179,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -190,6 +193,7 @@
 import java.util.TimeZone;
 import java.util.TreeSet;
 import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
 
 /**
@@ -230,8 +234,12 @@
 
     private static final long TEMPORARY_QUOTA_DURATION = INTERVAL_DAY;
 
-    // System property read on some device configurations to initialize time properly.
+    // System properties read on some device configurations to initialize time properly and
+    // perform DST transitions at the bootloader level.
     private static final String TIMEOFFSET_PROPERTY = "persist.sys.time.offset";
+    private static final String DST_TRANSITION_PROPERTY = "persist.sys.time.dst_transition";
+    private static final String DST_OFFSET_PROPERTY = "persist.sys.time.dst_offset";
+
 
     private final Intent mBackgroundIntent
             = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
@@ -2149,6 +2157,19 @@
 
             final int gmtOffset = newZone.getOffset(mInjector.getCurrentTimeMillis());
             SystemProperties.set(TIMEOFFSET_PROPERTY, String.valueOf(gmtOffset));
+
+            final ZoneRules rules = newZone.toZoneId().getRules();
+            final ZoneOffsetTransition transition = rules.nextTransition(Instant.now());
+            if (null != transition) {
+                // Get the offset between the time after the DST transition and before.
+                final long transitionOffset = TimeUnit.SECONDS.toMillis((
+                        transition.getOffsetAfter().getTotalSeconds()
+                        - transition.getOffsetBefore().getTotalSeconds()));
+                // Time when the next DST transition is programmed.
+                final long nextTransition = TimeUnit.SECONDS.toMillis(transition.toEpochSecond());
+                SystemProperties.set(DST_TRANSITION_PROPERTY, String.valueOf(nextTransition));
+                SystemProperties.set(DST_OFFSET_PROPERTY, String.valueOf(transitionOffset));
+            }
         }
 
         // Clear the default time zone in the system server process. This forces the next call