diff options
| author | 2022-09-12 14:15:19 +0100 | |
|---|---|---|
| committer | 2022-09-29 14:22:13 +0100 | |
| commit | c18a5de5e233c00c0ef0321793f2b99c58c0a0ca (patch) | |
| tree | e9253d27e19e9c51de857ea263d1db80ef4e9434 | |
| parent | 6bfc89fe6215a1ecaaad5706d46ecfc893b88ef0 (diff) | |
Disable kernel time zone offset-syncing behavior
Historically, Android's AlarmManagerService has tried to keep the kernel
informed when the current UTC offset might have changed, i.e. ultimately
it calls settimeofday() with a second argument.
The second argument contains a timezone struct containing the current
UTC offset (in seconds and reversed from the usual convention, i.e. US
time zones are considered a positive value). The struct technically
includes DST information but Android defaults this to 0.
Users of settimeofday() and gettimeofday() on Linux generally avoids use
of this time zone information as it is inherently not very useful.
AlarmManagerService's implementation is also imperfect: the current code
doesn't monitor the offset / next DST transition and so it will "miss"
the point when a DST transition occurs, leaving the offset incorrect
from that point. It does update the offset every 24 hours,
so it will eventually correct itself.
Rather than trying to improve the behavior, here we assume the behavior
is vestigial and unnecessary. It is disabled by this commit, but in a
way that can be restored easily later with a one-line change. It can be
stripped out fully in a later release.
Test: build / treehugger only
Bug: 246256335
Change-Id: I21efc63a232d52999b4b1c708441c01da91bfc73
| -rw-r--r-- | apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java | 68 |
1 files changed, 50 insertions, 18 deletions
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 8a823e22785c..c0f45d6fef1e 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -128,6 +128,7 @@ import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.Keep; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; @@ -216,6 +217,19 @@ public class AlarmManagerService extends SystemService { private static final long TEMPORARY_QUOTA_DURATION = INTERVAL_DAY; + /* + * b/246256335: This compile-time constant controls whether Android attempts to sync the Kernel + * time zone offset via settimeofday(null, tz). For <= Android T behavior is the same as + * {@code true}, the state for future releases is the same as {@code false}. + * It is unlikely anything depends on this, but a compile-time constant has been used to limit + * the size of the revert if this proves to be invorrect. The guarded code and associated + * methods / native code can be removed after release testing has proved that removing the + * behavior doesn't break anything. + * TODO(b/246256335): After this change has soaked for a release, remove this constant and + * everything it affects. + */ + private static final boolean KERNEL_TIME_ZONE_SYNC_ENABLED = false; + private final Intent mBackgroundIntent = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND); @@ -1884,10 +1898,12 @@ public class AlarmManagerService extends SystemService { mNextWakeup = mNextNonWakeup = 0; - // We set the current offset in kernel because the kernel doesn't keep this after a - // reboot. Keeping the kernel time zone in sync is "best effort" and can be wrong - // for a period after daylight savings transitions. - mInjector.syncKernelTimeZoneOffset(); + if (KERNEL_TIME_ZONE_SYNC_ENABLED) { + // We set the current offset in kernel because the kernel doesn't keep this after a + // reboot. Keeping the kernel time zone in sync is "best effort" and can be wrong + // for a period after daylight savings transitions. + mInjector.syncKernelTimeZoneOffset(); + } // Ensure that we're booting with a halfway sensible current time. Use the // most recent of Build.TIME, the root file system's timestamp, and the @@ -2122,14 +2138,17 @@ public class AlarmManagerService extends SystemService { final long currentTimeMillis = mInjector.getCurrentTimeMillis(); mInjector.setKernelTime(millis); - // Changing the time may cross a DST transition; sync the kernel offset if needed. - final TimeZone timeZone = TimeZone.getTimeZone(SystemTimeZone.getTimeZoneId()); - final int currentTzOffset = timeZone.getOffset(currentTimeMillis); - final int newTzOffset = timeZone.getOffset(millis); - if (currentTzOffset != newTzOffset) { - Slog.i(TAG, "Timezone offset has changed, updating kernel timezone"); - mInjector.setKernelTimeZoneOffset(newTzOffset); + if (KERNEL_TIME_ZONE_SYNC_ENABLED) { + // Changing the time may cross a DST transition; sync the kernel offset if needed. + final TimeZone timeZone = TimeZone.getTimeZone(SystemTimeZone.getTimeZoneId()); + final int currentTzOffset = timeZone.getOffset(currentTimeMillis); + final int newTzOffset = timeZone.getOffset(millis); + if (currentTzOffset != newTzOffset) { + Slog.i(TAG, "Timezone offset has changed, updating kernel timezone"); + mInjector.setKernelTimeZoneOffset(newTzOffset); + } } + // The native implementation of setKernelTime can return -1 even when the kernel // time was set correctly, so assume setting kernel time was successful and always // return true. @@ -2152,9 +2171,11 @@ public class AlarmManagerService extends SystemService { // newZone.getId(). It will be rejected if it is invalid. timeZoneWasChanged = SystemTimeZone.setTimeZoneId(tzId, confidence); - // Update the kernel timezone information - int utcOffsetMillis = newZone.getOffset(mInjector.getCurrentTimeMillis()); - mInjector.setKernelTimeZoneOffset(utcOffsetMillis); + if (KERNEL_TIME_ZONE_SYNC_ENABLED) { + // Update the kernel timezone information + int utcOffsetMillis = newZone.getOffset(mInjector.getCurrentTimeMillis()); + mInjector.setKernelTimeZoneOffset(utcOffsetMillis); + } } // Clear the default time zone in the system server process. This forces the next call @@ -4285,6 +4306,15 @@ public class AlarmManagerService extends SystemService { private static native int set(long nativeData, int type, long seconds, long nanoseconds); private static native int waitForAlarm(long nativeData); private static native int setKernelTime(long nativeData, long millis); + + /* + * b/246256335: The @Keep ensures that the native definition is kept even when the optimizer can + * tell no calls will be made due to a compile-time constant. Allowing this definition to be + * optimized away breaks loadLibrary("alarm_jni") at boot time. + * TODO(b/246256335): Remove this native method and the associated native code when it is no + * longer needed. + */ + @Keep private static native int setKernelTimezone(long nativeData, int minuteswest); private static native long getNextAlarm(long nativeData, int type); @@ -5031,10 +5061,12 @@ public class AlarmManagerService extends SystemService { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) { - // Since the kernel does not keep track of DST, we reset the TZ information at the - // beginning of each day. This may miss a DST transition, but it will correct itself - // within 24 hours. - mInjector.syncKernelTimeZoneOffset(); + if (KERNEL_TIME_ZONE_SYNC_ENABLED) { + // Since the kernel does not keep track of DST, we reset the TZ information at + // the beginning of each day. This may miss a DST transition, but it will + // correct itself within 24 hours. + mInjector.syncKernelTimeZoneOffset(); + } scheduleDateChangedEvent(); } } |