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

Commit 9cb260ac authored by Neil Fuller's avatar Neil Fuller Committed by Android (Google) Code Review
Browse files

Merge "Prepare to make origin list mutable" into sc-dev

parents 28bbba90 5b91a19e
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