Loading core/java/android/app/timedetector/TimeDetector.java +12 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,18 @@ import android.os.TimestampedValue; @SystemService(Context.TIME_DETECTOR_SERVICE) public interface TimeDetector { /** * The name of the service for shell commands. * @hide */ String SHELL_COMMAND_SERVICE_NAME = "time_detector"; /** * A shell command that prints the current "auto time detection" global setting value. * @hide */ String SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED = "is_auto_detection_enabled"; /** * A shared utility method to create a {@link ManualTimeSuggestion}. * Loading services/core/java/com/android/server/timedetector/EnvironmentImpl.java +3 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,9 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment { handleAutoTimeDetectionChangedOnHandlerThread(); } }); mServiceConfigAccessor.addListener( () -> mHandler.post( EnvironmentImpl.this::handleAutoTimeDetectionChangedOnHandlerThread)); } /** Internal method for handling the auto time setting being changed. */ Loading services/core/java/com/android/server/timedetector/ServerFlags.java +22 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,15 @@ public final class ServerFlags { public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT = "location_time_zone_detection_setting_enabled_default"; /** * The key to override the time detector origin priorities configuration. A comma-separated list * of strings that will be passed to {@link TimeDetectorStrategy#stringToOrigin(String)}. * All values must be recognized or the override value will be ignored. */ @DeviceConfigKey public static final String KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE = "time_detector_origin_priorities_override"; @GuardedBy("mListeners") private final ArrayMap<ConfigurationChangeListener, Set<String>> mListeners = new ArrayMap<>(); Loading Loading @@ -208,6 +217,19 @@ public final class ServerFlags { return Optional.ofNullable(value); } /** * Returns an optional string array value from {@link DeviceConfig} from the system_time * namespace, returns {@link Optional#empty()} if there is no explicit value set. */ @NonNull public Optional<String[]> getOptionalStringArray(@DeviceConfigKey String key) { Optional<String> string = getOptionalString(key); if (!string.isPresent()) { return Optional.empty(); } return Optional.of(string.get().split(",")); } /** * Returns an optional boolean value from {@link DeviceConfig} from the system_time * namespace, returns {@link Optional#empty()} if there is no explicit value set. Loading services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java +102 −17 Original line number Diff line number Diff line Loading @@ -15,9 +15,9 @@ */ package com.android.server.timedetector; 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 static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -28,12 +28,17 @@ import android.util.ArraySet; 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.Collections; 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 Loading @@ -48,7 +53,7 @@ final class ServiceConfigAccessor { * By default telephony and network only suggestions are accepted and telephony takes * precedence over network. */ private static final @TimeDetectorStrategy.Origin int[] private static final @Origin int[] DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES = { ORIGIN_TELEPHONY, ORIGIN_NETWORK }; /** Loading @@ -60,6 +65,7 @@ final class ServiceConfigAccessor { private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet( new ArraySet<>(new String[] { KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE, })); private static final Object SLOCK = new Object(); Loading @@ -70,8 +76,9 @@ final class ServiceConfigAccessor { private static ServiceConfigAccessor sInstance; @NonNull private final Context mContext; @NonNull private final ConfigOriginPrioritiesSupplier mConfigOriginPrioritiesSupplier; @NonNull private final ServerFlagsOriginPrioritiesSupplier mServerFlagsOriginPrioritiesSupplier; @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 Loading @@ -83,7 +90,9 @@ final class ServiceConfigAccessor { private ServiceConfigAccessor(@NonNull Context context) { mContext = Objects.requireNonNull(context); mServerFlags = ServerFlags.getInstance(mContext); mOriginPriorities = getOriginPrioritiesInternal(); mConfigOriginPrioritiesSupplier = new ConfigOriginPrioritiesSupplier(context); mServerFlagsOriginPrioritiesSupplier = new ServerFlagsOriginPrioritiesSupplier(mServerFlags); mSystemClockUpdateThresholdMillis = SystemProperties.getInt("ro.sys.time_detector_update_diff", SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT); Loading Loading @@ -111,8 +120,17 @@ final class ServiceConfigAccessor { } @NonNull int[] getOriginPriorities() { return mOriginPriorities; @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() { Loading @@ -123,19 +141,86 @@ final class ServiceConfigAccessor { 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; /** * 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(); } return origins; /** 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 +11 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ import android.app.timedetector.TelephonyTimeSuggestion; import android.content.Context; import android.os.Binder; import android.os.Handler; import android.os.ResultReceiver; import android.os.ShellCallback; import android.util.IndentingPrintWriter; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -100,6 +102,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { } @Override @NonNull public TimeCapabilitiesAndConfig getCapabilitiesAndConfig() { int userId = mCallerIdentityInjector.getCallingUserId(); return getTimeCapabilitiesAndConfig(userId); Loading @@ -119,7 +122,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { } @Override public boolean updateConfiguration(TimeConfiguration timeConfiguration) { public boolean updateConfiguration(@NonNull TimeConfiguration timeConfiguration) { enforceManageTimeDetectorPermission(); // TODO(b/172891783) Add actual logic return false; Loading Loading @@ -180,6 +183,13 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { ipw.flush(); } @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { new TimeDetectorShellCommand(this).exec( this, in, out, err, args, callback, resultReceiver); } private void enforceSuggestTelephonyTimePermission() { mContext.enforceCallingPermission( android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE, Loading Loading
core/java/android/app/timedetector/TimeDetector.java +12 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,18 @@ import android.os.TimestampedValue; @SystemService(Context.TIME_DETECTOR_SERVICE) public interface TimeDetector { /** * The name of the service for shell commands. * @hide */ String SHELL_COMMAND_SERVICE_NAME = "time_detector"; /** * A shell command that prints the current "auto time detection" global setting value. * @hide */ String SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED = "is_auto_detection_enabled"; /** * A shared utility method to create a {@link ManualTimeSuggestion}. * Loading
services/core/java/com/android/server/timedetector/EnvironmentImpl.java +3 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,9 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment { handleAutoTimeDetectionChangedOnHandlerThread(); } }); mServiceConfigAccessor.addListener( () -> mHandler.post( EnvironmentImpl.this::handleAutoTimeDetectionChangedOnHandlerThread)); } /** Internal method for handling the auto time setting being changed. */ Loading
services/core/java/com/android/server/timedetector/ServerFlags.java +22 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,15 @@ public final class ServerFlags { public static final String KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT = "location_time_zone_detection_setting_enabled_default"; /** * The key to override the time detector origin priorities configuration. A comma-separated list * of strings that will be passed to {@link TimeDetectorStrategy#stringToOrigin(String)}. * All values must be recognized or the override value will be ignored. */ @DeviceConfigKey public static final String KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE = "time_detector_origin_priorities_override"; @GuardedBy("mListeners") private final ArrayMap<ConfigurationChangeListener, Set<String>> mListeners = new ArrayMap<>(); Loading Loading @@ -208,6 +217,19 @@ public final class ServerFlags { return Optional.ofNullable(value); } /** * Returns an optional string array value from {@link DeviceConfig} from the system_time * namespace, returns {@link Optional#empty()} if there is no explicit value set. */ @NonNull public Optional<String[]> getOptionalStringArray(@DeviceConfigKey String key) { Optional<String> string = getOptionalString(key); if (!string.isPresent()) { return Optional.empty(); } return Optional.of(string.get().split(",")); } /** * Returns an optional boolean value from {@link DeviceConfig} from the system_time * namespace, returns {@link Optional#empty()} if there is no explicit value set. Loading
services/core/java/com/android/server/timedetector/ServiceConfigAccessor.java +102 −17 Original line number Diff line number Diff line Loading @@ -15,9 +15,9 @@ */ package com.android.server.timedetector; 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 static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -28,12 +28,17 @@ import android.util.ArraySet; 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.Collections; 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 Loading @@ -48,7 +53,7 @@ final class ServiceConfigAccessor { * By default telephony and network only suggestions are accepted and telephony takes * precedence over network. */ private static final @TimeDetectorStrategy.Origin int[] private static final @Origin int[] DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES = { ORIGIN_TELEPHONY, ORIGIN_NETWORK }; /** Loading @@ -60,6 +65,7 @@ final class ServiceConfigAccessor { private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet( new ArraySet<>(new String[] { KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE, })); private static final Object SLOCK = new Object(); Loading @@ -70,8 +76,9 @@ final class ServiceConfigAccessor { private static ServiceConfigAccessor sInstance; @NonNull private final Context mContext; @NonNull private final ConfigOriginPrioritiesSupplier mConfigOriginPrioritiesSupplier; @NonNull private final ServerFlagsOriginPrioritiesSupplier mServerFlagsOriginPrioritiesSupplier; @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 Loading @@ -83,7 +90,9 @@ final class ServiceConfigAccessor { private ServiceConfigAccessor(@NonNull Context context) { mContext = Objects.requireNonNull(context); mServerFlags = ServerFlags.getInstance(mContext); mOriginPriorities = getOriginPrioritiesInternal(); mConfigOriginPrioritiesSupplier = new ConfigOriginPrioritiesSupplier(context); mServerFlagsOriginPrioritiesSupplier = new ServerFlagsOriginPrioritiesSupplier(mServerFlags); mSystemClockUpdateThresholdMillis = SystemProperties.getInt("ro.sys.time_detector_update_diff", SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT); Loading Loading @@ -111,8 +120,17 @@ final class ServiceConfigAccessor { } @NonNull int[] getOriginPriorities() { return mOriginPriorities; @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() { Loading @@ -123,19 +141,86 @@ final class ServiceConfigAccessor { 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; /** * 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(); } return origins; /** 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 +11 −1 Original line number Diff line number Diff line Loading @@ -30,6 +30,8 @@ import android.app.timedetector.TelephonyTimeSuggestion; import android.content.Context; import android.os.Binder; import android.os.Handler; import android.os.ResultReceiver; import android.os.ShellCallback; import android.util.IndentingPrintWriter; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -100,6 +102,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { } @Override @NonNull public TimeCapabilitiesAndConfig getCapabilitiesAndConfig() { int userId = mCallerIdentityInjector.getCallingUserId(); return getTimeCapabilitiesAndConfig(userId); Loading @@ -119,7 +122,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { } @Override public boolean updateConfiguration(TimeConfiguration timeConfiguration) { public boolean updateConfiguration(@NonNull TimeConfiguration timeConfiguration) { enforceManageTimeDetectorPermission(); // TODO(b/172891783) Add actual logic return false; Loading Loading @@ -180,6 +183,13 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { ipw.flush(); } @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { new TimeDetectorShellCommand(this).exec( this, in, out, err, args, callback, resultReceiver); } private void enforceSuggestTelephonyTimePermission() { mContext.enforceCallingPermission( android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE, Loading