summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Neil Fuller <nfuller@google.com> 2022-09-12 14:15:19 +0100
committer Neil Fuller <nfuller@google.com> 2022-09-29 14:22:13 +0100
commitc18a5de5e233c00c0ef0321793f2b99c58c0a0ca (patch)
treee9253d27e19e9c51de857ea263d1db80ef4e9434
parent6bfc89fe6215a1ecaaad5706d46ecfc893b88ef0 (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.java68
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();
}
}