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

Commit 0068bae2 authored by Almaz Mingaleev's avatar Almaz Mingaleev
Browse files

Add lower bound checks for non-manual time suggestions.

Before this change, automatic time detection would not validate the incoming UTC time suggested. When the device time is set to a bad value it can cause problems with connectivity and fail enterprise policy checks.

After this change, automatic time detection (currently NITZ or NTP) will disregard times before a lower bound. The lower bound value is initially set from a date derived from the build timestamp. This works on the principle that a valid time cannot be before the system image was built. There is no upper bound currently as we haven't seen invalid dates in the future, and it's harder to come up with a timestamp that we know will always be invalid.

This change may impact automated or manual tests that use dates in the distant past: these dates will no longer be accepted. Tests will have to be updated to use dates in the future.

Bug: 172229867
Test: atest
frameworks/base/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java

Change-Id: I844ae06c3145e0fac30bd5455ec4f00d01b06ac8
parent 08466f61
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -20,12 +20,15 @@ import android.annotation.NonNull;
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Slog;

import java.time.Instant;
import java.util.Objects;

/**
@@ -37,6 +40,13 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat

    private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;

    /**
     * Time in the past. If automatic time suggestion is before this point, it's
     * incorrect for sure.
     */
    private static final Instant TIME_LOWER_BOUND = Instant.ofEpochMilli(
            Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));

    /**
     * If a newly calculated system clock time and the current system clock time differs by this or
     * more the system clock will actually be updated. Used to prevent the system clock being set
@@ -78,6 +88,11 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
        }
    }

    @Override
    public Instant autoTimeLowerBound() {
        return TIME_LOWER_BOUND;
    }

    @Override
    public void acquireWakeLock() {
        if (mWakeLock.isHeld()) {
+38 −10
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import com.android.server.timezonedetector.ReferenceWithHistory;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.time.Instant;

/**
 * An implementation of {@link TimeDetectorStrategy} that passes telephony and manual suggestions to
@@ -143,6 +144,15 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
        /** Returns true if automatic time detection is enabled. */
        boolean isAutoTimeDetectionEnabled();

        /**
         * Returns a lower bound for valid automatic times. It is guaranteed to be in the past,
         * i.e. it is unrelated to the current system clock time.
         * It holds no other meaning; it could be related to when the device system image was built,
         * or could be updated by a mainline module.
         */
        @NonNull
        Instant autoTimeLowerBound();

        /** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
        void acquireWakeLock();

@@ -177,7 +187,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {

    @Override
    public synchronized void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion) {
        if (!validateSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) {
        if (!validateAutoSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) {
            return;
        }

@@ -211,9 +221,12 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
            return;
        }

        // Perform validation / input filtering and record the validated suggestion against the
        // slotIndex.
        if (!validateAndStoreTelephonySuggestion(timeSuggestion)) {
        if (!validateAutoSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) {
            return;
        }

        // Perform input filtering and record the validated suggestion against the slotIndex.
        if (!storeTelephonySuggestion(timeSuggestion)) {
            return;
        }

@@ -272,14 +285,9 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
    }

    @GuardedBy("this")
    private boolean validateAndStoreTelephonySuggestion(
    private boolean storeTelephonySuggestion(
            @NonNull TelephonyTimeSuggestion suggestion) {
        TimestampedValue<Long> newUtcTime = suggestion.getUtcTime();
        if (!validateSuggestionTime(newUtcTime, suggestion)) {
            // There's probably nothing useful we can do: elsewhere we assume that reference
            // times are in the past so just stop here.
            return false;
        }

        int slotIndex = suggestion.getSlotIndex();
        TelephonyTimeSuggestion previousSuggestion = mSuggestionBySlotIndex.get(slotIndex);
@@ -330,6 +338,26 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
        return true;
    }

    private boolean validateAutoSuggestionTime(
            @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion)  {
        return validateSuggestionTime(newUtcTime, suggestion)
                && validateSuggestionAgainstLowerBound(newUtcTime, suggestion);
    }

    private boolean validateSuggestionAgainstLowerBound(
            @NonNull TimestampedValue<Long> newUtcTime, @NonNull Object suggestion) {
        Instant lowerBound = mCallback.autoTimeLowerBound();

        // Suggestion is definitely wrong if it comes before lower time bound.
        if (lowerBound.isAfter(Instant.ofEpochMilli(newUtcTime.getValue()))) {
            Slog.w(LOG_TAG, "Suggestion points to time before lower bound, skipping it. "
                    + "suggestion=" + suggestion + ", lower bound=" + lowerBound);
            return false;
        }

        return true;
    }

    @GuardedBy("this")
    private void doAutoTimeDetection(@NonNull String detectionReason) {
        if (!mCallback.isAutoTimeDetectionEnabled()) {
+132 −57

File changed.

Preview size limit exceeded, changes collapsed.