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

Commit 5ef61031 authored by Neil Fuller's avatar Neil Fuller
Browse files

Add NtpTrustedTime.forceRefresh(Network)

Add NtpTrustedTime.forceRefresh(Network). If a component that uses
NtpTrustedTime is monitoring network connectivity, it should probably
provide the network to be used, otherwise there is a non-obvious
relationship between the network being monitored and the network
actually used.

Only one user of NtpTrustedTime is updated here as the other,
GnssLocationProvider / NtpTimeHelper, is going to be refactored in an
upcoming commit. Leaving it using the forceRefresh() method that doesn't
take a parameter is not a regression.

Bug: 222295093
Test: atest core/tests/coretests/src/android/util/NtpTrustedTimeTest
Test: Treehugger
Change-Id: I51db528d06359c33335c874aca524f5adee3f3a7
parent 9a0c9f23
Loading
Loading
Loading
Loading
+120 −90
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * A singleton that connects with a remote NTP server as its trusted time source. This class
@@ -251,24 +250,47 @@ public abstract class NtpTrustedTime implements TrustedTime {
        }
    }

    /** Forces a refresh using the default network. */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public boolean forceRefresh() {
        synchronized (this) {
            NtpConfig ntpConfig = getNtpConfig();
            if (ntpConfig == null) {
                // missing server config, so no NTP time available
                if (LOGD) Log.d(TAG, "forceRefresh: invalid server config");
            Network network = getDefaultNetwork();
            if (network == null) {
                if (LOGD) Log.d(TAG, "forceRefresh: no network available");
                return false;
            }

            Network network = getNetwork();
            if (network == null) {
                if (LOGD) Log.d(TAG, "forceRefresh: no network available");
            return forceRefreshLocked(network);
        }
    }

    /** Forces a refresh using the specified network. */
    public boolean forceRefresh(@NonNull Network network) {
        Objects.requireNonNull(network);

        synchronized (this) {
            return forceRefreshLocked(network);
        }
    }

    @GuardedBy("this")
    private boolean forceRefreshLocked(@NonNull Network network) {
        Objects.requireNonNull(network);

        if (!isNetworkConnected(network)) {
            if (LOGD) Log.d(TAG, "forceRefreshLocked: network=" + network + " is not connected");
            return false;
        }

        NtpConfig ntpConfig = getNtpConfig();
        if (ntpConfig == null) {
            // missing server config, so no NTP time available
            if (LOGD) Log.d(TAG, "forceRefreshLocked: invalid server config");
            return false;
        }

        if (LOGD) {
                Log.d(TAG, "forceRefresh: NTP request network=" + network
            Log.d(TAG, "forceRefreshLocked: NTP request network=" + network
                    + " ntpConfig=" + ntpConfig);
        }

@@ -325,7 +347,6 @@ public abstract class NtpTrustedTime implements TrustedTime {
        }
        return false;
    }
    }

    @GuardedBy("this")
    private NtpConfig getNtpConfig() {
@@ -346,14 +367,23 @@ public abstract class NtpTrustedTime implements TrustedTime {
    public abstract NtpConfig getNtpConfigInternal();

    /**
     * Returns the {@link Network} to use during an NTP query. This method can return {@code null}
     * if there is no connectivity
     * Returns the default {@link Network} to use during an NTP query when no network is specified.
     * This method can return {@code null} if the device hasn't fully initialized or there is no
     * active network.
     *
     * <p>This method has been made public for easy replacement during tests.
     */
    @VisibleForTesting
    @Nullable
    public abstract Network getNetwork();
    public abstract Network getDefaultNetwork();

    /**
     * Returns {@code true} if there is likely to be connectivity on the supplied network.
     *
     * <p>This method has been made public for easy replacement during tests.
     */
    @VisibleForTesting
    public abstract boolean isNetworkConnected(@NonNull Network network);

    /**
     * Queries the specified NTP server. This is a blocking call. Returns {@code null} if the query
@@ -565,26 +595,9 @@ public abstract class NtpTrustedTime implements TrustedTime {
     */
    private static final class NtpTrustedTimeImpl extends NtpTrustedTime {

        /**
         * A supplier that returns the ConnectivityManager. The Supplier can return null if
         * ConnectivityService isn't running yet.
         */
        private final Supplier<ConnectivityManager> mConnectivityManagerSupplier =
                new Supplier<>() {
        @GuardedBy("this")
        private ConnectivityManager mConnectivityManager;

            @Nullable
            @Override
            public synchronized ConnectivityManager get() {
                // We can't do this at initialization time: ConnectivityService might not be running
                // yet.
                if (mConnectivityManager == null) {
                    mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
                }
                return mConnectivityManager;
            }
        };

        @NonNull
        private final Context mContext;

@@ -629,13 +642,20 @@ public abstract class NtpTrustedTime implements TrustedTime {
        }

        @Override
        public Network getNetwork() {
            ConnectivityManager connectivityManager = mConnectivityManagerSupplier.get();
        public Network getDefaultNetwork() {
            ConnectivityManager connectivityManager = getConnectivityManager();
            if (connectivityManager == null) {
                if (LOGD) Log.d(TAG, "getNetwork: no ConnectivityManager");
                return null;
            }
            final Network network = connectivityManager.getActiveNetwork();
            return connectivityManager.getActiveNetwork();
        }

        @Override
        public boolean isNetworkConnected(@NonNull Network network) {
            ConnectivityManager connectivityManager = getConnectivityManager();
            if (connectivityManager == null) {
                return false;
            }
            final NetworkInfo ni = connectivityManager.getNetworkInfo(network);

            // This connectivity check is to avoid performing a DNS lookup for the time server on a
@@ -649,9 +669,19 @@ public abstract class NtpTrustedTime implements TrustedTime {
            // addresses are actually reachable.
            if (ni == null || !ni.isConnected()) {
                if (LOGD) Log.d(TAG, "getNetwork: no connectivity");
                return null;
                return false;
            }
            return true;
        }
            return network;

        private synchronized ConnectivityManager getConnectivityManager() {
            if (mConnectivityManager == null) {
                mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
            }
            if (mConnectivityManager == null) {
                if (LOGD) Log.d(TAG, "getConnectivityManager: no ConnectivityManager");
            }
            return mConnectivityManager;
        }

        @Override
+107 −57

File changed.

Preview size limit exceeded, changes collapsed.

+38 −25
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import com.android.server.LocalServices;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.time.Duration;
import java.util.Objects;

/**
 * Monitors the network time. If looking up the network time fails for some reason, it tries a few
@@ -74,8 +75,6 @@ public class NetworkTimeUpdateService extends Binder {

    private static final int POLL_REQUEST = 0;

    private Network mDefaultNetwork = null;

    private final Context mContext;
    private final NtpTrustedTime mTime;
    private final AlarmManager mAlarmManager;
@@ -84,21 +83,12 @@ public class NetworkTimeUpdateService extends Binder {
    private final PendingIntent mPendingPollIntent;
    private final PowerManager.WakeLock mWakeLock;

    // NTP lookup is done on this thread and handler
    private Handler mHandler;
    private AutoTimeSettingObserver mAutoTimeSettingObserver;
    private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;

    // Normal polling frequency
    private final long mPollingIntervalMs;
    // Try-again polling interval, in case the network request failed
    private final long mPollingIntervalShorterMs;
    // Number of times to try again
    private final int mTryAgainTimesMax;
    // Keeps track of how many quick attempts were made to fetch NTP time.
    // During bootup, the network may not have been up yet, or it's taking time for the
    // connection to happen.
    private int mTryAgainCounter;

    /**
     * A log that records the decisions to fetch a network time update.
@@ -107,8 +97,26 @@ public class NetworkTimeUpdateService extends Binder {
    @NonNull
    private final LocalLog mLocalLog = new LocalLog(30, false /* useLocalTimestamps */);

    public NetworkTimeUpdateService(Context context) {
        mContext = context;
    // NTP lookup is done on this thread and handler
    // @NonNull after systemRunning()
    private Handler mHandler;
    // @NonNull after systemRunning()
    private AutoTimeSettingObserver mAutoTimeSettingObserver;
    // @NonNull after systemRunning()
    private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;

    // This field is only updated and accessed by the mHandler thread (except dump()).
    @Nullable
    private Network mDefaultNetwork = null;

    // Keeps track of how many quick attempts were made to fetch NTP time.
    // During bootup, the network may not have been up yet, or it's taking time for the
    // connection to happen.
    // This field is only updated and accessed by the mHandler thread (except dump()).
    private int mTryAgainCounter;

    public NetworkTimeUpdateService(@NonNull Context context) {
        mContext = Objects.requireNonNull(context);
        mTime = NtpTrustedTime.getInstance(context);
        mAlarmManager = mContext.getSystemService(AlarmManager.class);
        mTimeDetectorInternal = LocalServices.getService(TimeDetectorInternal.class);
@@ -205,23 +213,26 @@ public class NetworkTimeUpdateService extends Binder {

    private void onPollNetworkTime(int event) {
        // If we don't have any default network, don't bother.
        if (mDefaultNetwork == null) return;
        Network network = mDefaultNetwork;
        if (network == null) return;

        mWakeLock.acquire();
        try {
            onPollNetworkTimeUnderWakeLock(event);
            onPollNetworkTimeUnderWakeLock(network, event);
        } finally {
            mWakeLock.release();
        }
    }

    private void onPollNetworkTimeUnderWakeLock(int event) {
    private void onPollNetworkTimeUnderWakeLock(@NonNull Network network, int event) {
        long currentElapsedRealtimeMillis = SystemClock.elapsedRealtime();

        // Force an NTP fix when outdated
        NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult();
        if (cachedNtpResult == null || cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis)
                >= mPollingIntervalMs) {
            if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
            boolean isSuccessful = mTime.forceRefresh();
            if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh using network=" + network);
            boolean isSuccessful = mTime.forceRefresh(network);
            if (isSuccessful) {
                mTryAgainCounter = 0;
            } else {
@@ -265,7 +276,8 @@ public class NetworkTimeUpdateService extends Binder {
    }

    /** Suggests the time to the time detector. It may choose use it to set the system clock. */
    private void makeNetworkTimeSuggestion(TimeResult ntpResult, String debugInfo) {
    private void makeNetworkTimeSuggestion(
            @NonNull TimeResult ntpResult, @NonNull String debugInfo) {
        TimestampedValue<Long> timeSignal = new TimestampedValue<>(
                ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis());
        NetworkTimeSuggestion timeSuggestion =
@@ -295,7 +307,7 @@ public class NetworkTimeUpdateService extends Binder {
        }

        @Override
        public void handleMessage(Message msg) {
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case EVENT_AUTO_TIME_ENABLED:
                case EVENT_POLL_NETWORK_TIME:
@@ -308,7 +320,7 @@ public class NetworkTimeUpdateService extends Binder {

    private class NetworkTimeUpdateCallback extends NetworkCallback {
        @Override
        public void onAvailable(Network network) {
        public void onAvailable(@NonNull Network network) {
            Log.d(TAG, String.format("New default network %s; checking time.", network));
            mDefaultNetwork = network;
            // Running on mHandler so invoke directly.
@@ -316,7 +328,7 @@ public class NetworkTimeUpdateService extends Binder {
        }

        @Override
        public void onLost(Network network) {
        public void onLost(@NonNull Network network) {
            if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
        }
    }
@@ -331,10 +343,10 @@ public class NetworkTimeUpdateService extends Binder {
        private final int mMsg;
        private final Handler mHandler;

        AutoTimeSettingObserver(Context context, Handler handler, int msg) {
        AutoTimeSettingObserver(@NonNull Context context, @NonNull Handler handler, int msg) {
            super(handler);
            mContext = context;
            mHandler = handler;
            mContext = Objects.requireNonNull(context);
            mHandler = Objects.requireNonNull(handler);
            mMsg = msg;
        }

@@ -366,6 +378,7 @@ public class NetworkTimeUpdateService extends Binder {
        pw.println("mPollingIntervalMs=" + Duration.ofMillis(mPollingIntervalMs));
        pw.println("mPollingIntervalShorterMs=" + Duration.ofMillis(mPollingIntervalShorterMs));
        pw.println("mTryAgainTimesMax=" + mTryAgainTimesMax);
        pw.println("mDefaultNetwork=" + mDefaultNetwork);
        pw.println("mTryAgainCounter=" + mTryAgainCounter);
        pw.println();
        pw.println("NtpTrustedTime:");