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

Commit 55187e82 authored by Neil Fuller's avatar Neil Fuller
Browse files

Implement flag for auto tz detection default

For internal testing experiments, implement a server flag for affecting
the auto time zone detection default setting value when the device
hasn't had an explicit value set.

Implementation notes:

The usual "value is not set so use [flag controlled] default value"
cannot be used; the auto_time_zone global setting cannot be left unset.
The setting it is regrettably a public API and could be observed by
other components. Instead, the system keeps a record of whether the
setting value has been set (via selected APIs) in a new (non-public)
global setting (auto_time_zone_explicit).

When the flag is set the system attempts to keep the auto_time_zone
setting value in sync with the current behavior value in case other
things are observing the value.

Manual Testing
==============

The server flag can be set using:

  adb shell cmd device_config put system_time \
    time_zone_detector_auto_detection_enabled_default \
    [true|false]

... and unset using the delete verb of the same command:

  adb shell cmd device_config delete system_time \
    time_zone_detector_auto_detection_enabled_default

The existing setting can be read and set using:

  adb shell settings get global auto_time_zone
  adb shell settings put global auto_time_zone [0|1]

The new setting that controls whether the flag can be used can be
read/set/cleared for manual testing via:

  adb shell settings get global auto_time_zone_explicit
  adb shell settings put global auto_time_zone_explicit 1
  adb shell settings delete global auto_time_zone_explicit

time_zone_detector configuration state and debug logs can be read via:

  adb shell dumpsys time_zone_detector

Test: Manual testing with various scenarios, see above
Test: New test. See associated topic change in cts
Bug: 273403348
Change-Id: I7091d792428bf4884e6802a537e8cb6d8ecb674f
parent c95d515c
Loading
Loading
Loading
Loading
+31 −2
Original line number Diff line number Diff line
@@ -11796,7 +11796,13 @@ public final class Settings {
        /**
         * Value to specify if the device's UTC system clock should be set automatically, e.g. using
         * telephony signals like NITZ, or other sources like GNSS or NTP. 1=yes, 0=no (manual)
         * telephony signals like NITZ, or other sources like GNSS or NTP.
         *
         * <p>Prefer {@link android.app.time.TimeManager} API calls to determine the state of
         * automatic time detection instead of directly observing this setting as it may be ignored
         * by the time_detector service under various conditions.
         *
         * <p>1=yes, 0=no (manual)
         */
        @Readable
        public static final String AUTO_TIME = "auto_time";
@@ -11804,11 +11810,34 @@ public final class Settings {
        /**
         * Value to specify if the device's time zone system property should be set automatically,
         * e.g. using telephony signals like MCC and NITZ, or other mechanisms like the location.
         * 1=yes, 0=no (manual).
         *
         * <p>Prefer {@link android.app.time.TimeManager} API calls to determine the state of
         * automatic time zone detection instead of directly observing this setting as it may be
         * ignored by the time_zone_detector service under various conditions.
         *
         * <p>1=yes, 0=no (manual).
         */
        @Readable
        public static final String AUTO_TIME_ZONE = "auto_time_zone";
        /**
         * Records whether an explicit preference for {@link #AUTO_TIME_ZONE} has been expressed
         * instead of the current value being the default. This value is used to tell if the {@link
         * #AUTO_TIME_ZONE} value can be influenced by experiment flags that alter the setting's
         * value for internal testers: once the user indicates a preference they leave the
         * experiment, only users that are still using the default will be affected by the flag.
         *
         * <p>Since {@link #AUTO_TIME_ZONE} can be altered by components besides the system server,
         * and not just via the time_zone_detector logic that sets this value, this isn't guaranteed
         * to be set when the device diverges from the default in all cases. Important AOSP system
         * components like SettingsUI do use the time_zone_detector APIs.
         *
         * <p>1="has been set explicitly"
         *
         * @hide
         */
        public static final String AUTO_TIME_ZONE_EXPLICIT = "auto_time_zone_explicit";
        /**
         * URI for the car dock "in" event sound.
         * @hide
+1 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ public class SettingsBackupTest {
                    Settings.Global.AUTOFILL_LOGGING_LEVEL,
                    Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
                    Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
                    Settings.Global.AUTO_TIME_ZONE_EXPLICIT,
                    Settings.Global.AVERAGE_TIME_TO_DISCHARGE,
                    Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
                    Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME,
+9 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ public final class ServerFlags {
            KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
            KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE,
            KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE,
            KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT,
            KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED,
            KEY_ENHANCED_METRICS_COLLECTION_ENABLED,
    })
@@ -153,6 +154,14 @@ public final class ServerFlags {
            KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT =
            "location_time_zone_detection_setting_enabled_default";

    /**
     * The key to alter a device's "automatic time zone detection enabled" setting default value.
     * This flag is only intended for internal testing.
     */
    public static final @DeviceConfigKey String
            KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT =
            "time_zone_detector_auto_detection_enabled_default";

    /**
     * The key to control support for time zone detection falling back to telephony detection under
     * certain circumstances.
+45 −11
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
            ServerFlags.KEY_ENHANCED_METRICS_COLLECTION_ENABLED,
            ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT,
            ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE,
            ServerFlags.KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT,
            ServerFlags.KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED
    );

@@ -174,7 +175,7 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
            }
        }, filter, null, null /* main thread */);

        // Add async callbacks for global settings being changed.
        // Add async callbacks for changes to global settings that influence behavior.
        ContentResolver contentResolver = mContext.getContentResolver();
        ContentObserver contentObserver = new ContentObserver(mContext.getMainThreadHandler()) {
            @Override
@@ -184,6 +185,9 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
        };
        contentResolver.registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, contentObserver);
        contentResolver.registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE_EXPLICIT), true,
                contentObserver);

        // Add async callbacks for user scoped location settings being changed.
        contentResolver.registerContentObserver(
@@ -239,8 +243,9 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {

    @Override
    public synchronized boolean updateConfiguration(@UserIdInt int userId,
            @NonNull TimeZoneConfiguration requestedConfiguration, boolean bypassUserPolicyChecks) {
        Objects.requireNonNull(requestedConfiguration);
            @NonNull TimeZoneConfiguration requestedConfigurationUpdates,
            boolean bypassUserPolicyChecks) {
        Objects.requireNonNull(requestedConfigurationUpdates);

        ConfigurationInternal configurationInternal = getConfigurationInternal(userId);
        TimeZoneCapabilities capabilities =
@@ -248,7 +253,7 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
        TimeZoneConfiguration oldConfiguration = configurationInternal.asConfiguration();

        final TimeZoneConfiguration newConfiguration =
                capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfiguration);
                capabilities.tryApplyConfigChanges(oldConfiguration, requestedConfigurationUpdates);
        if (newConfiguration == null) {
            // The changes could not be made because the user's capabilities do not allow it.
            return false;
@@ -256,7 +261,7 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {

        // Store the configuration / notify as needed. This will cause the mEnvironment to invoke
        // handleConfigChanged() asynchronously.
        storeConfiguration(userId, newConfiguration);
        storeConfiguration(userId, requestedConfigurationUpdates, newConfiguration);

        return true;
    }
@@ -268,15 +273,20 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
     */
    @GuardedBy("this")
    private void storeConfiguration(@UserIdInt int userId,
            @NonNull TimeZoneConfiguration configuration) {
        Objects.requireNonNull(configuration);
            @NonNull TimeZoneConfiguration requestedConfigurationUpdates,
            @NonNull TimeZoneConfiguration newConfiguration) {
        Objects.requireNonNull(newConfiguration);

        // Avoid writing the auto detection enabled setting for devices that do not support auto
        // time zone detection: if we wrote it down then we'd set the value explicitly, which would
        // prevent detecting "default" later. That might influence what happens on later releases
        // that support new types of auto detection on the same hardware.
        if (isAutoDetectionFeatureSupported()) {
            final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
            if (requestedConfigurationUpdates.hasIsAutoDetectionEnabled()) {
                // Record that the auto detection enabled setting has now been set explicitly.
                Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE_EXPLICIT, 1);
            }
            final boolean autoDetectionEnabled = newConfiguration.isAutoDetectionEnabled();
            setAutoDetectionEnabledIfRequired(autoDetectionEnabled);

            // Only write the geo detection enabled setting when its values is used, e.g.:
@@ -288,10 +298,10 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
            // Not being able to detect if the user has actually expressed a preference could
            // influence what happens on later releases that start to support geo detection on the
            // user's same hardware.
            if (!getGeoDetectionSettingEnabledOverride().isPresent()
            if (getGeoDetectionSettingEnabledOverride().isEmpty()
                    && isGeoTimeZoneDetectionFeatureSupported()
                    && isTelephonyTimeZoneDetectionFeatureSupported()) {
                final boolean geoDetectionEnabledSetting = configuration.isGeoDetectionEnabled();
                final boolean geoDetectionEnabledSetting = newConfiguration.isGeoDetectionEnabled();
                setGeoDetectionEnabledSettingIfRequired(userId, geoDetectionEnabledSetting);
            }
        }
@@ -335,7 +345,31 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
    }

    private boolean getAutoDetectionEnabledSetting() {
        return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
        boolean autoDetectionEnabledSetting =
                Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;

        Optional<Boolean> optionalFlagValue = mServerFlags.getOptionalBoolean(
                ServerFlags.KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT);
        if (optionalFlagValue.isPresent()) {
            // This branch is rare: it is expected to happen only for internal testers.

            if (Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE_EXPLICIT, 0) == 0) {
                // The device hasn't explicitly had the auto detection enabled setting updated via a
                // call to storeConfiguration(). This means the device is allowed to use a server
                // flag to determine the default.
                boolean flagValue = optionalFlagValue.get();

                // Best effort to keep the setting in sync with the flag in case something is
                // observing the (public API) Settings.Global.AUTO_TIME_ZONE directly. This change
                // will cause listeners to fire asynchronously but any cascade should stop after one
                // round.
                if (flagValue != autoDetectionEnabledSetting) {
                    Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME_ZONE, flagValue ? 1 : 0);
                }
                autoDetectionEnabledSetting = flagValue;
            }
        }
        return autoDetectionEnabledSetting;
    }

    private boolean getGeoDetectionEnabledSetting(@UserIdInt int userId) {
+5 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE
import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_RUN_IN_BACKGROUND_ENABLED;
import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT;
import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE;
import static com.android.server.timedetector.ServerFlags.KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT;
import static com.android.server.timedetector.ServerFlags.KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED;

import android.app.time.LocationTimeZoneManager;
@@ -308,6 +309,10 @@ class TimeZoneDetectorShellCommand extends ShellCommand {
        pw.printf("  %s\n", KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE);
        pw.printf("    Used to override the device's 'geolocation time zone detection enabled'"
                + " setting [*].\n");
        pw.printf("  %s\n", KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT);
        pw.printf("    Used to set the automatic time zone detection enabled default, i.e. when the"
                + " device's automatic time zone detection enabled setting hasn't been set"
                + " explicitly. Intended for internal testers.");
        pw.printf("  %s\n", KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED);
        pw.printf("    Used to enable / disable support for telephony detection fallback. Also see"
                + " the %s command.\n", SHELL_COMMAND_ENABLE_TELEPHONY_FALLBACK);