Loading services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java +25 −188 Original line number Diff line number Diff line Loading @@ -15,214 +15,51 @@ */ package com.android.server.timedetector; import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE; import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE; import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK; import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.Build; import android.os.SystemProperties; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.server.timedetector.TimeDetectorStrategy.Origin; import com.android.server.timezonedetector.ConfigurationChangeListener; import java.time.Instant; import java.util.Arrays; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; /** * 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 @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)); /** Device config keys that affect the {@link TimeDetectorService}. */ private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Set.of( KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE, KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE ); 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 ConfigOriginPrioritiesSupplier mConfigOriginPrioritiesSupplier; @NonNull private final ServerFlagsOriginPrioritiesSupplier mServerFlagsOriginPrioritiesSupplier; @NonNull private final ServerFlags mServerFlags; /** * 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. * An interface that provides access to service configuration for time detection. This hides * how configuration is split between static, compile-time config, dynamic server-pushed flags and * user settings. It provides listeners to signal when values that affect different components have * changed. */ private final int mSystemClockUpdateThresholdMillis; private ServiceConfigAccessor(@NonNull Context context) { mContext = Objects.requireNonNull(context); mServerFlags = ServerFlags.getInstance(mContext); mConfigOriginPrioritiesSupplier = new ConfigOriginPrioritiesSupplier(context); mServerFlagsOriginPrioritiesSupplier = new ServerFlagsOriginPrioritiesSupplier(mServerFlags); 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; } } public interface ServiceConfigAccessor { /** * Adds a listener that will be called when server flags related to this class change. The * callbacks are delivered on the main looper thread. * Adds a listener that will be invoked when {@link ConfigurationInternal} may have changed. * The listener is invoked on the main 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 @Origin int[] getOriginPriorities() { int[] serverFlagsValue = mServerFlagsOriginPrioritiesSupplier.get(); if (serverFlagsValue != null) { return serverFlagsValue; } int[] configValue = mConfigOriginPrioritiesSupplier.get(); if (configValue != null) { return configValue; } return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES; } int systemClockUpdateThresholdMillis() { return mSystemClockUpdateThresholdMillis; } @NonNull Instant autoTimeLowerBound() { return mServerFlags.getOptionalInstant(KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE) .orElse(TIME_LOWER_BOUND_DEFAULT); } void addListener(@NonNull ConfigurationChangeListener listener); /** * A base supplier of an array of time origin integers in priority order. * It handles memoization of the result to avoid repeated string parsing when nothing has * changed. * Returns 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 need not be set. */ private abstract static class BaseOriginPrioritiesSupplier implements Supplier<@Origin int[]> { @GuardedBy("this") @Nullable private String[] mLastPriorityStrings; @GuardedBy("this") @Nullable private int[] mLastPriorityInts; /** Returns an array of {@code ORIGIN_*} values, or {@code null}. */ @Override @Nullable public @Origin int[] get() { String[] priorityStrings = lookupPriorityStrings(); synchronized (this) { if (Arrays.equals(mLastPriorityStrings, priorityStrings)) { return mLastPriorityInts; } int[] priorityInts = null; if (priorityStrings != null && priorityStrings.length > 0) { priorityInts = new int[priorityStrings.length]; try { for (int i = 0; i < priorityInts.length; i++) { String priorityString = priorityStrings[i]; Preconditions.checkArgument(priorityString != null); priorityString = priorityString.trim(); priorityInts[i] = TimeDetectorStrategy.stringToOrigin(priorityString); } } catch (IllegalArgumentException e) { // If any strings were bad and they were ignored then the semantics of the // whole list could change, so return null. priorityInts = null; } } mLastPriorityStrings = priorityStrings; mLastPriorityInts = priorityInts; return priorityInts; } } @Nullable protected abstract String[] lookupPriorityStrings(); } /** Supplies origin priorities from config_autoTimeSourcesPriority. */ private static class ConfigOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier { @NonNull private final Context mContext; private ConfigOriginPrioritiesSupplier(Context context) { mContext = Objects.requireNonNull(context); } @Override @Nullable protected String[] lookupPriorityStrings() { return mContext.getResources().getStringArray(R.array.config_autoTimeSourcesPriority); } } int systemClockUpdateThresholdMillis(); /** * Supplies origin priorities from device_config (server flags), see * {@link ServerFlags#KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE}. * 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. */ private static class ServerFlagsOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier { @NonNull private final ServerFlags mServerFlags; private ServerFlagsOriginPrioritiesSupplier(ServerFlags serverFlags) { mServerFlags = Objects.requireNonNull(serverFlags); } @NonNull Instant autoTimeLowerBound(); @Override @Nullable protected String[] lookupPriorityStrings() { Optional<String[]> priorityStrings = mServerFlags.getOptionalStringArray( KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE); return priorityStrings.orElse(null); } } /** * Returns the order to look at time suggestions when automatically detecting time. * See {@code #ORIGIN_} constants */ @NonNull @Origin int[] getOriginPriorities(); } services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java 0 → 100644 +229 −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.ServerFlags.KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE; import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE; import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK; import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.Build; import android.os.SystemProperties; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.server.timedetector.TimeDetectorStrategy.Origin; import com.android.server.timezonedetector.ConfigurationChangeListener; import java.time.Instant; import java.util.Arrays; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; /** * A singleton implementation of {@link ServiceConfigAccessor}. */ final class ServiceConfigAccessorImpl implements 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 @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)); /** Device config keys that affect the {@link TimeDetectorService}. */ private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Set.of( KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE, KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE ); 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 ConfigOriginPrioritiesSupplier mConfigOriginPrioritiesSupplier; @NonNull private final ServerFlagsOriginPrioritiesSupplier mServerFlagsOriginPrioritiesSupplier; /** * 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 ServiceConfigAccessorImpl(@NonNull Context context) { mContext = Objects.requireNonNull(context); mServerFlags = ServerFlags.getInstance(mContext); mConfigOriginPrioritiesSupplier = new ConfigOriginPrioritiesSupplier(context); mServerFlagsOriginPrioritiesSupplier = new ServerFlagsOriginPrioritiesSupplier(mServerFlags); 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 ServiceConfigAccessorImpl(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. */ public void addListener(@NonNull ConfigurationChangeListener listener) { mServerFlags.addListener(listener, SERVER_FLAGS_KEYS_TO_WATCH); } @Override @NonNull public @Origin int[] getOriginPriorities() { int[] serverFlagsValue = mServerFlagsOriginPrioritiesSupplier.get(); if (serverFlagsValue != null) { return serverFlagsValue; } int[] configValue = mConfigOriginPrioritiesSupplier.get(); if (configValue != null) { return configValue; } return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES; } @Override public int systemClockUpdateThresholdMillis() { return mSystemClockUpdateThresholdMillis; } @Override @NonNull public Instant autoTimeLowerBound() { return mServerFlags.getOptionalInstant(KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE) .orElse(TIME_LOWER_BOUND_DEFAULT); } /** * A base supplier of an array of time origin integers in priority order. * It handles memoization of the result to avoid repeated string parsing when nothing has * changed. */ private abstract static class BaseOriginPrioritiesSupplier implements Supplier<@Origin int[]> { @GuardedBy("this") @Nullable private String[] mLastPriorityStrings; @GuardedBy("this") @Nullable private int[] mLastPriorityInts; /** Returns an array of {@code ORIGIN_*} values, or {@code null}. */ @Override @Nullable public @Origin int[] get() { String[] priorityStrings = lookupPriorityStrings(); synchronized (this) { if (Arrays.equals(mLastPriorityStrings, priorityStrings)) { return mLastPriorityInts; } int[] priorityInts = null; if (priorityStrings != null && priorityStrings.length > 0) { priorityInts = new int[priorityStrings.length]; try { for (int i = 0; i < priorityInts.length; i++) { String priorityString = priorityStrings[i]; Preconditions.checkArgument(priorityString != null); priorityString = priorityString.trim(); priorityInts[i] = TimeDetectorStrategy.stringToOrigin(priorityString); } } catch (IllegalArgumentException e) { // If any strings were bad and they were ignored then the semantics of the // whole list could change, so return null. priorityInts = null; } } mLastPriorityStrings = priorityStrings; mLastPriorityInts = priorityInts; return priorityInts; } } @Nullable protected abstract String[] lookupPriorityStrings(); } /** Supplies origin priorities from config_autoTimeSourcesPriority. */ private static class ConfigOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier { @NonNull private final Context mContext; private ConfigOriginPrioritiesSupplier(Context context) { mContext = Objects.requireNonNull(context); } @Override @Nullable protected String[] lookupPriorityStrings() { return mContext.getResources().getStringArray(R.array.config_autoTimeSourcesPriority); } } /** * Supplies origin priorities from device_config (server flags), see * {@link ServerFlags#KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE}. */ private static class ServerFlagsOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier { @NonNull private final ServerFlags mServerFlags; private ServerFlagsOriginPrioritiesSupplier(ServerFlags serverFlags) { mServerFlags = Objects.requireNonNull(serverFlags); } @Override @Nullable protected String[] lookupPriorityStrings() { Optional<String[]> priorityStrings = mServerFlags.getOptionalStringArray( KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE); return priorityStrings.orElse(null); } } } services/core/java/com/android/server/timedetector/TimeDetectorService.java +1 −1 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { Handler handler = FgThread.getHandler(); ServiceConfigAccessor serviceConfigAccessor = ServiceConfigAccessor.getInstance(context); ServiceConfigAccessorImpl.getInstance(context); TimeDetectorStrategy timeDetectorStrategy = TimeDetectorStrategyImpl.create(context, handler, serviceConfigAccessor); Loading Loading
services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java +25 −188 Original line number Diff line number Diff line Loading @@ -15,214 +15,51 @@ */ package com.android.server.timedetector; import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE; import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE; import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK; import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.Build; import android.os.SystemProperties; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.server.timedetector.TimeDetectorStrategy.Origin; import com.android.server.timezonedetector.ConfigurationChangeListener; import java.time.Instant; import java.util.Arrays; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; /** * 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 @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)); /** Device config keys that affect the {@link TimeDetectorService}. */ private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Set.of( KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE, KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE ); 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 ConfigOriginPrioritiesSupplier mConfigOriginPrioritiesSupplier; @NonNull private final ServerFlagsOriginPrioritiesSupplier mServerFlagsOriginPrioritiesSupplier; @NonNull private final ServerFlags mServerFlags; /** * 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. * An interface that provides access to service configuration for time detection. This hides * how configuration is split between static, compile-time config, dynamic server-pushed flags and * user settings. It provides listeners to signal when values that affect different components have * changed. */ private final int mSystemClockUpdateThresholdMillis; private ServiceConfigAccessor(@NonNull Context context) { mContext = Objects.requireNonNull(context); mServerFlags = ServerFlags.getInstance(mContext); mConfigOriginPrioritiesSupplier = new ConfigOriginPrioritiesSupplier(context); mServerFlagsOriginPrioritiesSupplier = new ServerFlagsOriginPrioritiesSupplier(mServerFlags); 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; } } public interface ServiceConfigAccessor { /** * Adds a listener that will be called when server flags related to this class change. The * callbacks are delivered on the main looper thread. * Adds a listener that will be invoked when {@link ConfigurationInternal} may have changed. * The listener is invoked on the main 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 @Origin int[] getOriginPriorities() { int[] serverFlagsValue = mServerFlagsOriginPrioritiesSupplier.get(); if (serverFlagsValue != null) { return serverFlagsValue; } int[] configValue = mConfigOriginPrioritiesSupplier.get(); if (configValue != null) { return configValue; } return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES; } int systemClockUpdateThresholdMillis() { return mSystemClockUpdateThresholdMillis; } @NonNull Instant autoTimeLowerBound() { return mServerFlags.getOptionalInstant(KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE) .orElse(TIME_LOWER_BOUND_DEFAULT); } void addListener(@NonNull ConfigurationChangeListener listener); /** * A base supplier of an array of time origin integers in priority order. * It handles memoization of the result to avoid repeated string parsing when nothing has * changed. * Returns 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 need not be set. */ private abstract static class BaseOriginPrioritiesSupplier implements Supplier<@Origin int[]> { @GuardedBy("this") @Nullable private String[] mLastPriorityStrings; @GuardedBy("this") @Nullable private int[] mLastPriorityInts; /** Returns an array of {@code ORIGIN_*} values, or {@code null}. */ @Override @Nullable public @Origin int[] get() { String[] priorityStrings = lookupPriorityStrings(); synchronized (this) { if (Arrays.equals(mLastPriorityStrings, priorityStrings)) { return mLastPriorityInts; } int[] priorityInts = null; if (priorityStrings != null && priorityStrings.length > 0) { priorityInts = new int[priorityStrings.length]; try { for (int i = 0; i < priorityInts.length; i++) { String priorityString = priorityStrings[i]; Preconditions.checkArgument(priorityString != null); priorityString = priorityString.trim(); priorityInts[i] = TimeDetectorStrategy.stringToOrigin(priorityString); } } catch (IllegalArgumentException e) { // If any strings were bad and they were ignored then the semantics of the // whole list could change, so return null. priorityInts = null; } } mLastPriorityStrings = priorityStrings; mLastPriorityInts = priorityInts; return priorityInts; } } @Nullable protected abstract String[] lookupPriorityStrings(); } /** Supplies origin priorities from config_autoTimeSourcesPriority. */ private static class ConfigOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier { @NonNull private final Context mContext; private ConfigOriginPrioritiesSupplier(Context context) { mContext = Objects.requireNonNull(context); } @Override @Nullable protected String[] lookupPriorityStrings() { return mContext.getResources().getStringArray(R.array.config_autoTimeSourcesPriority); } } int systemClockUpdateThresholdMillis(); /** * Supplies origin priorities from device_config (server flags), see * {@link ServerFlags#KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE}. * 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. */ private static class ServerFlagsOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier { @NonNull private final ServerFlags mServerFlags; private ServerFlagsOriginPrioritiesSupplier(ServerFlags serverFlags) { mServerFlags = Objects.requireNonNull(serverFlags); } @NonNull Instant autoTimeLowerBound(); @Override @Nullable protected String[] lookupPriorityStrings() { Optional<String[]> priorityStrings = mServerFlags.getOptionalStringArray( KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE); return priorityStrings.orElse(null); } } /** * Returns the order to look at time suggestions when automatically detecting time. * See {@code #ORIGIN_} constants */ @NonNull @Origin int[] getOriginPriorities(); }
services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java 0 → 100644 +229 −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.ServerFlags.KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE; import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE; import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK; import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.Build; import android.os.SystemProperties; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.server.timedetector.TimeDetectorStrategy.Origin; import com.android.server.timezonedetector.ConfigurationChangeListener; import java.time.Instant; import java.util.Arrays; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; /** * A singleton implementation of {@link ServiceConfigAccessor}. */ final class ServiceConfigAccessorImpl implements 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 @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)); /** Device config keys that affect the {@link TimeDetectorService}. */ private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Set.of( KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE, KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE ); 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 ConfigOriginPrioritiesSupplier mConfigOriginPrioritiesSupplier; @NonNull private final ServerFlagsOriginPrioritiesSupplier mServerFlagsOriginPrioritiesSupplier; /** * 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 ServiceConfigAccessorImpl(@NonNull Context context) { mContext = Objects.requireNonNull(context); mServerFlags = ServerFlags.getInstance(mContext); mConfigOriginPrioritiesSupplier = new ConfigOriginPrioritiesSupplier(context); mServerFlagsOriginPrioritiesSupplier = new ServerFlagsOriginPrioritiesSupplier(mServerFlags); 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 ServiceConfigAccessorImpl(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. */ public void addListener(@NonNull ConfigurationChangeListener listener) { mServerFlags.addListener(listener, SERVER_FLAGS_KEYS_TO_WATCH); } @Override @NonNull public @Origin int[] getOriginPriorities() { int[] serverFlagsValue = mServerFlagsOriginPrioritiesSupplier.get(); if (serverFlagsValue != null) { return serverFlagsValue; } int[] configValue = mConfigOriginPrioritiesSupplier.get(); if (configValue != null) { return configValue; } return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES; } @Override public int systemClockUpdateThresholdMillis() { return mSystemClockUpdateThresholdMillis; } @Override @NonNull public Instant autoTimeLowerBound() { return mServerFlags.getOptionalInstant(KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE) .orElse(TIME_LOWER_BOUND_DEFAULT); } /** * A base supplier of an array of time origin integers in priority order. * It handles memoization of the result to avoid repeated string parsing when nothing has * changed. */ private abstract static class BaseOriginPrioritiesSupplier implements Supplier<@Origin int[]> { @GuardedBy("this") @Nullable private String[] mLastPriorityStrings; @GuardedBy("this") @Nullable private int[] mLastPriorityInts; /** Returns an array of {@code ORIGIN_*} values, or {@code null}. */ @Override @Nullable public @Origin int[] get() { String[] priorityStrings = lookupPriorityStrings(); synchronized (this) { if (Arrays.equals(mLastPriorityStrings, priorityStrings)) { return mLastPriorityInts; } int[] priorityInts = null; if (priorityStrings != null && priorityStrings.length > 0) { priorityInts = new int[priorityStrings.length]; try { for (int i = 0; i < priorityInts.length; i++) { String priorityString = priorityStrings[i]; Preconditions.checkArgument(priorityString != null); priorityString = priorityString.trim(); priorityInts[i] = TimeDetectorStrategy.stringToOrigin(priorityString); } } catch (IllegalArgumentException e) { // If any strings were bad and they were ignored then the semantics of the // whole list could change, so return null. priorityInts = null; } } mLastPriorityStrings = priorityStrings; mLastPriorityInts = priorityInts; return priorityInts; } } @Nullable protected abstract String[] lookupPriorityStrings(); } /** Supplies origin priorities from config_autoTimeSourcesPriority. */ private static class ConfigOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier { @NonNull private final Context mContext; private ConfigOriginPrioritiesSupplier(Context context) { mContext = Objects.requireNonNull(context); } @Override @Nullable protected String[] lookupPriorityStrings() { return mContext.getResources().getStringArray(R.array.config_autoTimeSourcesPriority); } } /** * Supplies origin priorities from device_config (server flags), see * {@link ServerFlags#KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE}. */ private static class ServerFlagsOriginPrioritiesSupplier extends BaseOriginPrioritiesSupplier { @NonNull private final ServerFlags mServerFlags; private ServerFlagsOriginPrioritiesSupplier(ServerFlags serverFlags) { mServerFlags = Objects.requireNonNull(serverFlags); } @Override @Nullable protected String[] lookupPriorityStrings() { Optional<String[]> priorityStrings = mServerFlags.getOptionalStringArray( KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE); return priorityStrings.orElse(null); } } }
services/core/java/com/android/server/timedetector/TimeDetectorService.java +1 −1 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { Handler handler = FgThread.getHandler(); ServiceConfigAccessor serviceConfigAccessor = ServiceConfigAccessor.getInstance(context); ServiceConfigAccessorImpl.getInstance(context); TimeDetectorStrategy timeDetectorStrategy = TimeDetectorStrategyImpl.create(context, handler, serviceConfigAccessor); Loading