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

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

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
parent 6bfc89fe
Loading
Loading
Loading
Loading
+50 −18
Original line number Diff line number Diff line
@@ -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;

            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,6 +2138,7 @@ public class AlarmManagerService extends SystemService {
            final long currentTimeMillis = mInjector.getCurrentTimeMillis();
            mInjector.setKernelTime(millis);

            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);
@@ -2130,6 +2147,8 @@ public class AlarmManagerService extends SystemService {
                    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,10 +2171,12 @@ public class AlarmManagerService extends SystemService {
            // newZone.getId(). It will be rejected if it is invalid.
            timeZoneWasChanged = SystemTimeZone.setTimeZoneId(tzId, confidence);

            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
        // to TimeZone.getDefault() to re-read the device settings.
@@ -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.
                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();
            }
        }