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

Commit a61f367f authored by Neil Fuller's avatar Neil Fuller Committed by Automerger Merge Worker
Browse files

Merge "Prepare to make origin list mutable" into sc-dev am: 9cb260ac

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14185372

Change-Id: I57ad594fa1ae4936b36f75e5f0f907e0d39a7121
parents ba3c5d8f 9cb260ac
Loading
Loading
Loading
Loading
+50 −61
Original line number Diff line number Diff line
@@ -16,26 +16,22 @@

package com.android.server.timedetector;

import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;

import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Build;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Slog;

import com.android.internal.R;
import com.android.server.timedetector.TimeDetectorStrategy.Origin;
import com.android.internal.annotations.GuardedBy;
import com.android.server.timezonedetector.ConfigurationChangeListener;

import java.time.Instant;
import java.util.Objects;
@@ -43,62 +39,71 @@ import java.util.Objects;
/**
 * The real implementation of {@link TimeDetectorStrategyImpl.Environment} used on device.
 */
public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {

    private static final String TAG = TimeDetectorService.TAG;

    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(android.os.Environment.getRootDirectory().lastModified(), Build.TIME));

    /**
     * By default telephony and network only suggestions are accepted and telephony takes
     * precedence over network.
     */
    private static final @Origin int[] DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES =
            { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {

    /**
     * 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
     * for only minor differences.
     */
    private final int mSystemClockUpdateThresholdMillis;
    private static final String LOG_TAG = TimeDetectorService.TAG;

    @NonNull private final Context mContext;
    @NonNull private final Handler mHandler;
    @NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
    @NonNull private final ContentResolver mContentResolver;
    @NonNull private final PowerManager.WakeLock mWakeLock;
    @NonNull private final AlarmManager mAlarmManager;
    @NonNull private final UserManager mUserManager;
    @NonNull private final int[] mOriginPriorities;

    public EnvironmentImpl(@NonNull Context context) {
    // @NonNull after setConfigChangeListener() is called.
    @GuardedBy("this")
    private ConfigurationChangeListener mConfigChangeListener;

    EnvironmentImpl(@NonNull Context context, @NonNull Handler handler,
            @NonNull ServiceConfigAccessor serviceConfigAccessor) {
        mContext = Objects.requireNonNull(context);
        mContentResolver = Objects.requireNonNull(context.getContentResolver());
        mHandler = Objects.requireNonNull(handler);
        mServiceConfigAccessor = Objects.requireNonNull(serviceConfigAccessor);

        PowerManager powerManager = context.getSystemService(PowerManager.class);
        mWakeLock = Objects.requireNonNull(
                powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG));
                powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG));

        mAlarmManager = Objects.requireNonNull(context.getSystemService(AlarmManager.class));

        mUserManager = Objects.requireNonNull(context.getSystemService(UserManager.class));

        mSystemClockUpdateThresholdMillis =
                SystemProperties.getInt("ro.sys.time_detector_update_diff",
                        SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
        // Wire up the config change listeners. All invocations are performed on the mHandler
        // thread.

        mOriginPriorities = getOriginPriorities(context);
        ContentResolver contentResolver = context.getContentResolver();
        contentResolver.registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
                new ContentObserver(mHandler) {
                    @Override
                    public void onChange(boolean selfChange) {
                        handleAutoTimeDetectionChangedOnHandlerThread();
                    }
                });
    }

    /** Internal method for handling the auto time setting being changed. */
    private void handleAutoTimeDetectionChangedOnHandlerThread() {
        synchronized (this) {
            if (mConfigChangeListener == null) {
                Slog.wtf(LOG_TAG, "mConfigChangeListener is unexpectedly null");
            }
            mConfigChangeListener.onChange();
        }
    }

    @Override
    public void setConfigChangeListener(@NonNull ConfigurationChangeListener listener) {
        synchronized (this) {
            mConfigChangeListener = Objects.requireNonNull(listener);
        }
    }

    @Override
    public int systemClockUpdateThresholdMillis() {
        return mSystemClockUpdateThresholdMillis;
        return mServiceConfigAccessor.systemClockUpdateThresholdMillis();
    }

    @Override
@@ -112,12 +117,12 @@ public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environme

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

    @Override
    public int[] autoOriginPriorities() {
        return mOriginPriorities;
        return mServiceConfigAccessor.getOriginPriorities();
    }

    @Override
@@ -131,7 +136,7 @@ public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environme
    @Override
    public void acquireWakeLock() {
        if (mWakeLock.isHeld()) {
            Slog.wtf(TAG, "WakeLock " + mWakeLock + " already held");
            Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " already held");
        }
        mWakeLock.acquire();
    }
@@ -160,7 +165,7 @@ public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environme

    private void checkWakeLockHeld() {
        if (!mWakeLock.isHeld()) {
            Slog.wtf(TAG, "WakeLock " + mWakeLock + " not held");
            Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " not held");
        }
    }

@@ -168,20 +173,4 @@ public final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environme
        UserHandle userHandle = UserHandle.of(userId);
        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_DATE_TIME, userHandle);
    }

    private static int[] getOriginPriorities(@NonNull Context context) {
        String[] originStrings =
                context.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
        if (originStrings.length == 0) {
            return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
        } else {
            int[] origins = new int[originStrings.length];
            for (int i = 0; i < originStrings.length; i++) {
                int origin = stringToOrigin(originStrings[i]);
                origins[i] = origin;
            }

            return origins;
        }
    }
}
+141 −0
Original line number Diff line number Diff line
/*
 * Copyright 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.server.timedetector;

import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.Build;
import android.os.SystemProperties;
import android.util.ArraySet;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.server.timezonedetector.ConfigurationChangeListener;

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

/**
 * A singleton that provides access to service configuration for time detection. This hides how
 * configuration is split between static, compile-time config and dynamic, server-pushed flags. It
 * provides a rudimentary mechanism to signal when values have changed.
 */
final class ServiceConfigAccessor {

    private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;

    /**
     * By default telephony and network only suggestions are accepted and telephony takes
     * precedence over network.
     */
    private static final @TimeDetectorStrategy.Origin int[]
            DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES = { ORIGIN_TELEPHONY, ORIGIN_NETWORK };

    /**
     * Time in the past. If an automatic time suggestion is before this point, it is sure to be
     * incorrect.
     */
    private static final Instant TIME_LOWER_BOUND_DEFAULT = Instant.ofEpochMilli(
            Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME));

    private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet(
            new ArraySet<>(new String[] {
            }));

    private static final Object SLOCK = new Object();

    /** The singleton instance. Initialized once in {@link #getInstance(Context)}. */
    @GuardedBy("SLOCK")
    @Nullable
    private static ServiceConfigAccessor sInstance;

    @NonNull private final Context mContext;
    @NonNull private final ServerFlags mServerFlags;
    @NonNull private final int[] mOriginPriorities;

    /**
     * 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
     * for only minor differences.
     */
    private final int mSystemClockUpdateThresholdMillis;

    private ServiceConfigAccessor(@NonNull Context context) {
        mContext = Objects.requireNonNull(context);
        mServerFlags = ServerFlags.getInstance(mContext);
        mOriginPriorities = getOriginPrioritiesInternal();
        mSystemClockUpdateThresholdMillis =
                SystemProperties.getInt("ro.sys.time_detector_update_diff",
                        SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
    }

    /** Returns the singleton instance. */
    static ServiceConfigAccessor getInstance(Context context) {
        synchronized (SLOCK) {
            if (sInstance == null) {
                sInstance = new ServiceConfigAccessor(context);
            }
            return sInstance;
        }
    }

    /**
     * Adds a listener that will be called when server flags related to this class change. The
     * callbacks are delivered on the main looper thread.
     *
     * <p>Note: Only for use by long-lived objects. There is deliberately no associated remove
     * method.
     */
    void addListener(@NonNull ConfigurationChangeListener listener) {
        mServerFlags.addListener(listener, SERVER_FLAGS_KEYS_TO_WATCH);
    }

    @NonNull
    int[] getOriginPriorities() {
        return mOriginPriorities;
    }

    int systemClockUpdateThresholdMillis() {
        return mSystemClockUpdateThresholdMillis;
    }

    Instant autoTimeLowerBound() {
        return TIME_LOWER_BOUND_DEFAULT;
    }

    private int[] getOriginPrioritiesInternal() {
        String[] originStrings =
                mContext.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
        if (originStrings.length == 0) {
            return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
        } else {
            int[] origins = new int[originStrings.length];
            for (int i = 0; i < originStrings.length; i++) {
                int origin = stringToOrigin(originStrings[i]);
                origins[i] = origin;
            }

            return origins;
        }
    }
}
+10 −32
Original line number Diff line number Diff line
@@ -27,12 +27,9 @@ import android.app.timedetector.ITimeDetectorService;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Binder;
import android.os.Handler;
import android.provider.Settings;
import android.util.IndentingPrintWriter;

import com.android.internal.annotations.VisibleForTesting;
@@ -64,7 +61,16 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {

        @Override
        public void onStart() {
            TimeDetectorService service = TimeDetectorService.create(getContext());
            Context context = getContext();
            Handler handler = FgThread.getHandler();

            ServiceConfigAccessor serviceConfigAccessor =
                    ServiceConfigAccessor.getInstance(context);
            TimeDetectorStrategy timeDetectorStrategy =
                    TimeDetectorStrategyImpl.create(context, handler, serviceConfigAccessor);

            TimeDetectorService service =
                    new TimeDetectorService(context, handler, timeDetectorStrategy);

            // Publish the binder service so it can be accessed from other (appropriately
            // permissioned) processes.
@@ -77,28 +83,6 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
    @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
    @NonNull private final CallerIdentityInjector mCallerIdentityInjector;

    private static TimeDetectorService create(@NonNull Context context) {
        TimeDetectorStrategyImpl.Environment environment = new EnvironmentImpl(context);
        TimeDetectorStrategy timeDetectorStrategy = new TimeDetectorStrategyImpl(environment);

        Handler handler = FgThread.getHandler();
        TimeDetectorService timeDetectorService =
                new TimeDetectorService(context, handler, timeDetectorStrategy);

        // Wire up event listening.
        ContentResolver contentResolver = context.getContentResolver();
        contentResolver.registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
                new ContentObserver(handler) {
                    @Override
                    public void onChange(boolean selfChange) {
                        timeDetectorService.handleAutoTimeDetectionChanged();
                    }
                });

        return timeDetectorService;
    }

    @VisibleForTesting
    public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
            @NonNull TimeDetectorStrategy timeDetectorStrategy) {
@@ -185,12 +169,6 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
        mHandler.post(() -> mTimeDetectorStrategy.suggestExternalTime(timeSignal));
    }

    /** Internal method for handling the auto time setting being changed. */
    @VisibleForTesting
    public void handleAutoTimeDetectionChanged() {
        mHandler.post(mTimeDetectorStrategy::handleAutoTimeConfigChanged);
    }

    @Override
    protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
            @Nullable String[] args) {
+0 −6
Original line number Diff line number Diff line
@@ -92,12 +92,6 @@ public interface TimeDetectorStrategy extends Dumpable {
    /** Returns the configuration that controls time detector behaviour for specified user. */
    ConfigurationInternal getConfigurationInternal(@UserIdInt int userId);

    /**
     * Handles the auto-time configuration changing For example, when the auto-time setting is
     * toggled on or off.
     */
    void handleAutoTimeConfigChanged();

    // Utility methods below are to be moved to a better home when one becomes more obvious.

    /**
+21 −2
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
import android.content.Context;
import android.os.Handler;
import android.os.TimestampedValue;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
@@ -37,6 +39,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.timezonedetector.ArrayMapWithHistory;
import com.android.server.timezonedetector.ConfigurationChangeListener;
import com.android.server.timezonedetector.ReferenceWithHistory;

import java.time.Instant;
@@ -131,6 +134,12 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
     */
    public interface Environment {

        /**
         * Sets a {@link ConfigurationChangeListener} that will be invoked when there are any
         * changes that could affect time detection. This is invoked during system server setup.
         */
        void setConfigChangeListener(@NonNull ConfigurationChangeListener listener);

        /**
         * The absolute threshold below which the system clock need not be updated. i.e. if setting
         * the system clock would adjust it by less than this (either backwards or forwards) then it
@@ -178,8 +187,19 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
        void releaseWakeLock();
    }

    static TimeDetectorStrategy create(
            @NonNull Context context, @NonNull Handler handler,
            @NonNull ServiceConfigAccessor serviceConfigAccessor) {

        TimeDetectorStrategyImpl.Environment environment =
                new EnvironmentImpl(context, handler, serviceConfigAccessor);
        return new TimeDetectorStrategyImpl(environment);
    }

    @VisibleForTesting
    TimeDetectorStrategyImpl(@NonNull Environment environment) {
        mEnvironment = Objects.requireNonNull(environment);
        mEnvironment.setConfigChangeListener(this::handleAutoTimeConfigChanged);
    }

    @Override
@@ -279,8 +299,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
        return mEnvironment.configurationInternal(userId);
    }

    @Override
    public synchronized void handleAutoTimeConfigChanged() {
    private synchronized void handleAutoTimeConfigChanged() {
        boolean enabled = mEnvironment.isAutoTimeDetectionEnabled();
        // When automatic time detection is enabled we update the system clock instantly if we can.
        // Conversely, when automatic time detection is disabled we leave the clock as it is.
Loading