diff options
9 files changed, 295 insertions, 270 deletions
diff --git a/core/java/android/app/time/LocationTimeZoneManager.java b/core/java/android/app/time/LocationTimeZoneManager.java index 066aadae1476..f506f12a7ba0 100644 --- a/core/java/android/app/time/LocationTimeZoneManager.java +++ b/core/java/android/app/time/LocationTimeZoneManager.java @@ -50,31 +50,6 @@ public final class LocationTimeZoneManager { public static final String SHELL_COMMAND_STOP = "stop"; /** - * A shell command that can put providers into different modes. Takes effect next time the - * service is started. - */ - public static final String SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE = - "set_provider_mode_override"; - - /** - * The default provider mode. - * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}. - */ - public static final String PROVIDER_MODE_OVERRIDE_NONE = "none"; - - /** - * The "simulated" provider mode. - * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}. - */ - public static final String PROVIDER_MODE_OVERRIDE_SIMULATED = "simulated"; - - /** - * The "disabled" provider mode (equivalent to there being no provider configured). - * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}. - */ - public static final String PROVIDER_MODE_OVERRIDE_DISABLED = "disabled"; - - /** * A shell command that tells the service to record state information during tests. The next * argument value is "true" or "false". */ diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 180fc124f92e..cbd6b797c3b6 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1637,32 +1637,22 @@ config_timeZoneRulesUpdateTrackingEnabled are true.] --> <integer name="config_timeZoneRulesCheckRetryCount">5</integer> - <!-- Whether the geolocation time zone detection feature is enabled. --> + <!-- Whether the geolocation time zone detection feature is enabled. Setting this to false means + the feature cannot be used. Setting this to true means it may be used if other + configuration allows (see provider configuration below, also compile time overlays). --> <bool name="config_enableGeolocationTimeZoneDetection" translatable="false">true</bool> - <!-- Whether the primary LocationTimeZoneProvider is enabled device. + <!-- Whether the primary LocationTimeZoneProvider is enabled. Ignored if config_enableGeolocationTimeZoneDetection is false --> <bool name="config_enablePrimaryLocationTimeZoneProvider" translatable="false">false</bool> - <!-- Used when enablePrimaryLocationTimeZoneProvider is true. Controls whether to enable primary - location time zone provider overlay which allows the primary location time zone provider to - be replaced by an app at run-time. When disabled, only the - config_primaryLocationTimeZoneProviderPackageName package will be searched for the primary - location time zone provider, otherwise any system package is eligible. Anyone who wants to - disable the runtime overlay mechanism can set it to false. --> - <bool name="config_enablePrimaryLocationTimeZoneOverlay" translatable="false">false</bool> - <!-- Package name providing the primary location time zone provider. Used only when - config_enablePrimaryLocationTimeZoneOverlay is false. --> + <!-- The package name providing the primary location time zone provider. + Only used when config_enableGeolocationTimeZoneDetection and + enablePrimaryLocationTimeZoneProvider are true. --> <string name="config_primaryLocationTimeZoneProviderPackageName" translatable="false">@null</string> - <!-- Whether the secondary LocationTimeZoneProvider is enabled device. + <!-- Whether the secondary LocationTimeZoneProvider is enabled. Ignored if config_enableGeolocationTimeZoneDetection is false --> <bool name="config_enableSecondaryLocationTimeZoneProvider" translatable="false">true</bool> - <!-- Used when enableSecondaryLocationTimeZoneProvider is true. Controls whether to enable - secondary location time zone provider overlay which allows the primary location time zone - provider to config_secondaryLocationTimeZoneProviderPackageName package will be searched - for the secondary location time zone provider, otherwise any system package is eligible. - Anyone who wants to disable the runtime overlay mechanism can set it to false. --> - <bool name="config_enableSecondaryLocationTimeZoneOverlay" translatable="false">false</bool> <!-- Package name providing the secondary location time zone provider. Used only when config_enableSecondaryLocationTimeZoneOverlay is false. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index eb1fe1dd367d..408620a13aad 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2180,10 +2180,8 @@ <java-symbol type="bool" name="config_enableGnssTimeUpdateService" /> <java-symbol type="bool" name="config_enableGeolocationTimeZoneDetection" /> <java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneProvider" /> - <java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneOverlay" /> <java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" /> <java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneProvider" /> - <java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneOverlay" /> <java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" /> <java-symbol type="layout" name="resolver_list" /> diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java index 52ff48b6a277..d91e9c258548 100644 --- a/services/core/java/com/android/server/timedetector/ServerFlags.java +++ b/services/core/java/com/android/server/timedetector/ServerFlags.java @@ -28,6 +28,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.server.timezonedetector.ConfigurationChangeListener; import com.android.server.timezonedetector.ServiceConfigAccessor; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.time.Duration; import java.util.Map; import java.util.Objects; @@ -53,14 +55,15 @@ public final class ServerFlags { */ @StringDef(prefix = "KEY_", value = { KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED, - KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE, - KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE, + KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE, + KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE, KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS, KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS, KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS, KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE, KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, }) + @Retention(RetentionPolicy.SOURCE) @interface DeviceConfigKey {} /** @@ -75,19 +78,19 @@ public final class ServerFlags { /** * The key for the server flag that can override the device config for whether the primary - * location time zone provider is enabled or disabled. + * location time zone provider is enabled, disabled, or (for testing) in simulation mode. */ @DeviceConfigKey - public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE = - "primary_location_time_zone_provider_enabled_override"; + public static final String KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE = + "primary_location_time_zone_provider_mode_override"; /** * The key for the server flag that can override the device config for whether the secondary - * location time zone provider is enabled or disabled. + * location time zone provider is enabled or disabled, or (for testing) in simulation mode. */ @DeviceConfigKey - public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE = - "secondary_location_time_zone_provider_enabled_override"; + public static final String KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE = + "secondary_location_time_zone_provider_mode_override"; /** * The key for the minimum delay after location time zone detection has been enabled before the @@ -196,6 +199,16 @@ public final class ServerFlags { } /** + * Returns an optional string value from {@link DeviceConfig} from the system_time + * namespace, returns {@link Optional#empty()} if there is no explicit value set. + */ + @NonNull + public Optional<String> getOptionalString(@DeviceConfigKey String key) { + String value = DeviceConfig.getProperty(NAMESPACE_SYSTEM_TIME, key); + return Optional.ofNullable(value); + } + + /** * Returns an optional boolean value from {@link DeviceConfig} from the system_time * namespace, returns {@link Optional#empty()} if there is no explicit value set. */ diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java index 222e852728f5..50d37f42e889 100644 --- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java +++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessor.java @@ -17,6 +17,7 @@ package com.android.server.timezonedetector; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.StringDef; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; @@ -27,6 +28,10 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.server.timedetector.ServerFlags; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.time.Duration; import java.util.Collections; import java.util.Objects; @@ -40,13 +45,38 @@ import java.util.Set; */ public final class ServiceConfigAccessor { + @StringDef(prefix = "PROVIDER_MODE_", + value = { PROVIDER_MODE_SIMULATED, PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED}) + @Retention(RetentionPolicy.SOURCE) + @Target(ElementType.TYPE_USE) + @interface ProviderMode {} + + /** + * The "simulated" provider mode. + * For use with {@link #getPrimaryLocationTimeZoneProviderMode()} and {@link + * #getSecondaryLocationTimeZoneProviderMode()}. + */ + public static final @ProviderMode String PROVIDER_MODE_SIMULATED = "simulated"; + + /** + * The "disabled" provider mode. For use with {@link #getPrimaryLocationTimeZoneProviderMode()} + * and {@link #getSecondaryLocationTimeZoneProviderMode()}. + */ + public static final @ProviderMode String PROVIDER_MODE_DISABLED = "disabled"; + + /** + * The "enabled" provider mode. For use with {@link #getPrimaryLocationTimeZoneProviderMode()} + * and {@link #getSecondaryLocationTimeZoneProviderMode()}. + */ + public static final @ProviderMode String PROVIDER_MODE_ENABLED = "enabled"; + private static final Set<String> SERVER_FLAGS_KEYS_TO_WATCH = Collections.unmodifiableSet( new ArraySet<>(new String[] { ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED, ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE, - ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE, - ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE, + ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE, + ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE, ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS, ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS, ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS @@ -139,14 +169,28 @@ public final class ServiceConfigAccessor { /** * Returns {@code true} if the location-based time zone detection feature is supported on the - * device. This can be used during feature testing on builds that are capable of location time - * zone detection to enable / disable the feature for some users. + * device. */ public boolean isGeoTimeZoneDetectionFeatureSupported() { + // For the feature to be enabled it must: + // 1) Be turned on in config. + // 2) Not be turned off via a server flag. + // 3) There must be at least one location time zone provider enabled / configured. return mGeoDetectionFeatureSupportedInConfig - && isGeoTimeZoneDetectionFeatureSupportedInternal(); + && isGeoTimeZoneDetectionFeatureSupportedInternal() + && atLeastOneProviderIsEnabled(); + } + + private boolean atLeastOneProviderIsEnabled() { + return !(Objects.equals(getPrimaryLocationTimeZoneProviderMode(), PROVIDER_MODE_DISABLED) + && Objects.equals(getSecondaryLocationTimeZoneProviderMode(), + PROVIDER_MODE_DISABLED)); } + /** + * Returns {@code true} if the location-based time zone detection feature is not explicitly + * disabled by a server flag. + */ private boolean isGeoTimeZoneDetectionFeatureSupportedInternal() { final boolean defaultEnabled = true; return mServerFlags.getBoolean( @@ -154,42 +198,49 @@ public final class ServiceConfigAccessor { defaultEnabled); } + @NonNull + public String getPrimaryLocationTimeZoneProviderPackageName() { + return mContext.getResources().getString( + R.string.config_primaryLocationTimeZoneProviderPackageName); + } + + @NonNull + public String getSecondaryLocationTimeZoneProviderPackageName() { + return mContext.getResources().getString( + R.string.config_secondaryLocationTimeZoneProviderPackageName); + } + /** * Returns {@code true} if the primary location time zone provider can be used. */ - public boolean isPrimaryLocationTimeZoneProviderEnabled() { - return getPrimaryLocationTimeZoneProviderEnabledOverride() - .orElse(isPrimaryLocationTimeZoneProviderEnabledInConfig()); - } - - private boolean isPrimaryLocationTimeZoneProviderEnabledInConfig() { - int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider; - return getConfigBoolean(providerEnabledConfigId); + @NonNull + public @ProviderMode String getPrimaryLocationTimeZoneProviderMode() { + return mServerFlags.getOptionalString( + ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE) + .orElse(getPrimaryLocationTimeZoneProviderModeFromConfig()); } @NonNull - private Optional<Boolean> getPrimaryLocationTimeZoneProviderEnabledOverride() { - return mServerFlags.getOptionalBoolean( - ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE); + private @ProviderMode String getPrimaryLocationTimeZoneProviderModeFromConfig() { + int providerEnabledConfigId = R.bool.config_enablePrimaryLocationTimeZoneProvider; + return getConfigBoolean(providerEnabledConfigId) + ? PROVIDER_MODE_ENABLED : PROVIDER_MODE_DISABLED; } /** - * Returns {@code true} if the secondary location time zone provider can be used. + * Returns the mode for the secondary location time zone provider can be used. */ - public boolean isSecondaryLocationTimeZoneProviderEnabled() { - return getSecondaryLocationTimeZoneProviderEnabledOverride() - .orElse(isSecondaryLocationTimeZoneProviderEnabledInConfig()); - } - - private boolean isSecondaryLocationTimeZoneProviderEnabledInConfig() { - int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider; - return getConfigBoolean(providerEnabledConfigId); + public @ProviderMode String getSecondaryLocationTimeZoneProviderMode() { + return mServerFlags.getOptionalString( + ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE) + .orElse(getSecondaryLocationTimeZoneProviderModeFromConfig()); } @NonNull - private Optional<Boolean> getSecondaryLocationTimeZoneProviderEnabledOverride() { - return mServerFlags.getOptionalBoolean( - ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_ENABLED_OVERRIDE); + private @ProviderMode String getSecondaryLocationTimeZoneProviderModeFromConfig() { + int providerEnabledConfigId = R.bool.config_enableSecondaryLocationTimeZoneProvider; + return getConfigBoolean(providerEnabledConfigId) + ? PROVIDER_MODE_ENABLED : PROVIDER_MODE_DISABLED; } /** diff --git a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java index fb2a18493b7d..d2190fdc5bea 100644 --- a/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java +++ b/services/core/java/com/android/server/timezonedetector/location/ControllerImpl.java @@ -30,6 +30,7 @@ import static com.android.server.timezonedetector.location.TimeZoneProviderEvent import static com.android.server.timezonedetector.location.TimeZoneProviderEvent.EVENT_TYPE_UNCERTAIN; import android.annotation.DurationMillisLong; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.RemoteCallback; @@ -604,14 +605,14 @@ class ControllerImpl extends LocationTimeZoneProviderController { * known provider, then the command is logged and discarded. */ void handleProviderTestCommand( - @NonNull String providerName, @NonNull TestCommand testCommand, + @IntRange(from = 0, to = 1) int providerIndex, @NonNull TestCommand testCommand, @Nullable RemoteCallback callback) { mThreadingDomain.assertCurrentThread(); - LocationTimeZoneProvider targetProvider = getLocationTimeZoneProvider(providerName); + LocationTimeZoneProvider targetProvider = getLocationTimeZoneProvider(providerIndex); if (targetProvider == null) { warnLog("Unable to process test command:" - + " providerName=" + providerName + ", testCommand=" + testCommand); + + " providerIndex=" + providerIndex + ", testCommand=" + testCommand); return; } @@ -620,7 +621,7 @@ class ControllerImpl extends LocationTimeZoneProviderController { targetProvider.handleTestCommand(testCommand, callback); } catch (Exception e) { warnLog("Unable to process test command:" - + " providerName=" + providerName + ", testCommand=" + testCommand, e); + + " providerIndex=" + providerIndex + ", testCommand=" + testCommand, e); } } } @@ -658,14 +659,15 @@ class ControllerImpl extends LocationTimeZoneProviderController { } @Nullable - private LocationTimeZoneProvider getLocationTimeZoneProvider(@NonNull String providerName) { + private LocationTimeZoneProvider getLocationTimeZoneProvider( + @IntRange(from = 0, to = 1) int providerIndex) { LocationTimeZoneProvider targetProvider; - if (Objects.equals(mPrimaryProvider.getName(), providerName)) { + if (providerIndex == 0) { targetProvider = mPrimaryProvider; - } else if (Objects.equals(mSecondaryProvider.getName(), providerName)) { + } else if (providerIndex == 1) { targetProvider = mSecondaryProvider; } else { - warnLog("Bad providerName=" + providerName); + warnLog("Bad providerIndex=" + providerIndex); targetProvider = null; } return targetProvider; diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java index ca4a6408cfbb..3c5eacd98d55 100644 --- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java +++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerService.java @@ -16,13 +16,12 @@ package com.android.server.timezonedetector.location; -import static android.app.time.LocationTimeZoneManager.PRIMARY_PROVIDER_NAME; -import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DISABLED; -import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE; -import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED; -import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME; import static android.app.time.LocationTimeZoneManager.SERVICE_NAME; +import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_DISABLED; +import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_SIMULATED; + +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -37,12 +36,12 @@ import android.util.IndentingPrintWriter; import android.util.Log; import android.util.Slog; -import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.FgThread; import com.android.server.SystemService; +import com.android.server.timezonedetector.Dumpable; import com.android.server.timezonedetector.ServiceConfigAccessor; import com.android.server.timezonedetector.TimeZoneDetectorInternal; import com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderMetricsLogger; @@ -139,11 +138,15 @@ public class LocationTimeZoneManagerService extends Binder { private static final String ATTRIBUTION_TAG = "LocationTimeZoneService"; - private static final String PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION = - TimeZoneProviderService.PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE; - private static final String SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION = - TimeZoneProviderService.SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE; + @GuardedBy("mSharedLock") + private final ProviderConfig mPrimaryProviderConfig = new ProviderConfig( + 0 /* index */, "primary", + TimeZoneProviderService.PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE); + @GuardedBy("mSharedLock") + private final ProviderConfig mSecondaryProviderConfig = new ProviderConfig( + 1 /* index */, "secondary", + TimeZoneProviderService.SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE); @NonNull private final Context mContext; @@ -173,14 +176,6 @@ public class LocationTimeZoneManagerService extends Binder { @GuardedBy("mSharedLock") private ControllerEnvironmentImpl mEnvironment; - @GuardedBy("mSharedLock") - @NonNull - private String mPrimaryProviderModeOverride = PROVIDER_MODE_OVERRIDE_NONE; - - @GuardedBy("mSharedLock") - @NonNull - private String mSecondaryProviderModeOverride = PROVIDER_MODE_OVERRIDE_NONE; - LocationTimeZoneManagerService(Context context) { mContext = context.createAttributionContext(ATTRIBUTION_TAG); mHandler = FgThread.getHandler(); @@ -208,9 +203,14 @@ public class LocationTimeZoneManagerService extends Binder { mThreadingDomain.assertCurrentThread(); synchronized (mSharedLock) { - // Stop and start the service, waiting until completion. - stopOnDomainThread(); - startOnDomainThread(); + // Avoid starting the service if it is currently stopped. This is required because + // server flags are used by tests to set behavior with the service stopped, and we don't + // want the service being restarted after each flag is set. + if (mLocationTimeZoneDetectorController != null) { + // Stop and start the service, waiting until completion. + stopOnDomainThread(); + startOnDomainThread(); + } } } @@ -265,8 +265,8 @@ public class LocationTimeZoneManagerService extends Binder { } if (mLocationTimeZoneDetectorController == null) { - LocationTimeZoneProvider primary = createPrimaryProvider(); - LocationTimeZoneProvider secondary = createSecondaryProvider(); + LocationTimeZoneProvider primary = mPrimaryProviderConfig.createProvider(); + LocationTimeZoneProvider secondary = mSecondaryProviderConfig.createProvider(); ControllerImpl controller = new ControllerImpl(mThreadingDomain, primary, secondary); @@ -281,88 +281,6 @@ public class LocationTimeZoneManagerService extends Binder { } } - @NonNull - private LocationTimeZoneProvider createPrimaryProvider() { - LocationTimeZoneProviderProxy proxy; - if (isProviderInSimulationMode(PRIMARY_PROVIDER_NAME)) { - proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain); - } else if (!isProviderEnabled(PRIMARY_PROVIDER_NAME)) { - proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain); - } else { - proxy = new RealLocationTimeZoneProviderProxy( - mContext, - mHandler, - mThreadingDomain, - PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION, - R.bool.config_enablePrimaryLocationTimeZoneOverlay, - R.string.config_primaryLocationTimeZoneProviderPackageName - ); - } - ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(0); - return new BinderLocationTimeZoneProvider( - providerMetricsLogger, mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy); - } - - @NonNull - private LocationTimeZoneProvider createSecondaryProvider() { - LocationTimeZoneProviderProxy proxy; - if (isProviderInSimulationMode(SECONDARY_PROVIDER_NAME)) { - proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain); - } else if (!isProviderEnabled(SECONDARY_PROVIDER_NAME)) { - proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain); - } else { - proxy = new RealLocationTimeZoneProviderProxy( - mContext, - mHandler, - mThreadingDomain, - SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION, - R.bool.config_enableSecondaryLocationTimeZoneOverlay, - R.string.config_secondaryLocationTimeZoneProviderPackageName - ); - } - ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(1); - return new BinderLocationTimeZoneProvider( - providerMetricsLogger, mThreadingDomain, SECONDARY_PROVIDER_NAME, proxy); - } - - /** Used for bug triage and in tests to simulate provider events. */ - private boolean isProviderInSimulationMode(@NonNull String providerName) { - return isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_SIMULATED); - } - - /** Used for bug triage, and by tests and experiments to remove a provider. */ - private boolean isProviderEnabled(@NonNull String providerName) { - if (isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_DISABLED)) { - return false; - } - - switch (providerName) { - case PRIMARY_PROVIDER_NAME: { - return mServiceConfigAccessor.isPrimaryLocationTimeZoneProviderEnabled(); - } - case SECONDARY_PROVIDER_NAME: { - return mServiceConfigAccessor.isSecondaryLocationTimeZoneProviderEnabled(); - } - default: { - throw new IllegalArgumentException(providerName); - } - } - } - - private boolean isProviderModeOverrideSet(@NonNull String providerName, @NonNull String mode) { - switch (providerName) { - case PRIMARY_PROVIDER_NAME: { - return Objects.equals(mPrimaryProviderModeOverride, mode); - } - case SECONDARY_PROVIDER_NAME: { - return Objects.equals(mSecondaryProviderModeOverride, mode); - } - default: { - throw new IllegalArgumentException(providerName); - } - } - } - /** * Stops the service for tests and other rare cases. To avoid tests needing to sleep, this * method will not return until all the system server components have stopped. @@ -398,33 +316,6 @@ public class LocationTimeZoneManagerService extends Binder { } /** Sets this service into provider state recording mode for tests. */ - void setProviderModeOverride(@NonNull String providerName, @NonNull String mode) { - enforceManageTimeZoneDetectorPermission(); - - Preconditions.checkArgument( - PRIMARY_PROVIDER_NAME.equals(providerName) - || SECONDARY_PROVIDER_NAME.equals(providerName)); - Preconditions.checkArgument(PROVIDER_MODE_OVERRIDE_DISABLED.equals(mode) - || PROVIDER_MODE_OVERRIDE_SIMULATED.equals(mode) - || PROVIDER_MODE_OVERRIDE_NONE.equals(mode)); - - mThreadingDomain.postAndWait(() -> { - synchronized (mSharedLock) { - switch (providerName) { - case PRIMARY_PROVIDER_NAME: { - mPrimaryProviderModeOverride = mode; - break; - } - case SECONDARY_PROVIDER_NAME: { - mSecondaryProviderModeOverride = mode; - break; - } - } - } - }, BLOCKING_OP_WAIT_DURATION_MILLIS); - } - - /** Sets this service into provider state recording mode for tests. */ void setProviderStateRecordingEnabled(boolean enabled) { enforceManageTimeZoneDetectorPermission(); @@ -462,8 +353,8 @@ public class LocationTimeZoneManagerService extends Binder { * Passes a {@link TestCommand} to the specified provider and waits for the response. */ @NonNull - Bundle handleProviderTestCommand( - @NonNull String providerName, @NonNull TestCommand testCommand) { + Bundle handleProviderTestCommand(@IntRange(from = 0, to = 1) int providerIndex, + @NonNull TestCommand testCommand) { enforceManageTimeZoneDetectorPermission(); // Because this method blocks and posts work to the threading domain thread, it would cause @@ -484,7 +375,7 @@ public class LocationTimeZoneManagerService extends Binder { return; } mLocationTimeZoneDetectorController.handleProviderTestCommand( - providerName, testCommand, remoteCallback); + providerIndex, testCommand, remoteCallback); } }); @@ -510,6 +401,17 @@ public class LocationTimeZoneManagerService extends Binder { synchronized (mSharedLock) { ipw.println("LocationTimeZoneManagerService:"); ipw.increaseIndent(); + + ipw.println("Primary provider config:"); + ipw.increaseIndent(); + mPrimaryProviderConfig.dump(ipw, args); + ipw.decreaseIndent(); + + ipw.println("Secondary provider config:"); + ipw.increaseIndent(); + mSecondaryProviderConfig.dump(ipw, args); + ipw.decreaseIndent(); + if (mLocationTimeZoneDetectorController == null) { ipw.println("{Stopped}"); } else { @@ -546,4 +448,75 @@ public class LocationTimeZoneManagerService extends Binder { android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION, "manage time and time zone detection"); } + + /** An inner class for managing a provider's config. */ + private final class ProviderConfig implements Dumpable { + @IntRange(from = 0, to = 1) private final int mIndex; + @NonNull private final String mName; + @NonNull private final String mServiceAction; + + ProviderConfig(@IntRange(from = 0, to = 1) int index, @NonNull String name, + @NonNull String serviceAction) { + Preconditions.checkArgument(index >= 0 && index <= 1); + mIndex = index; + mName = Objects.requireNonNull(name); + mServiceAction = Objects.requireNonNull(serviceAction); + } + + @NonNull + LocationTimeZoneProvider createProvider() { + LocationTimeZoneProviderProxy proxy = createProxy(); + ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(mIndex); + return new BinderLocationTimeZoneProvider( + providerMetricsLogger, mThreadingDomain, mName, proxy); + } + + @GuardedBy("mSharedLock") + @Override + public void dump(IndentingPrintWriter ipw, String[] args) { + ipw.printf("getMode()=%s\n", getMode()); + ipw.printf("getPackageName()=%s\n", getPackageName()); + } + + @NonNull + private LocationTimeZoneProviderProxy createProxy() { + String mode = getMode(); + if (Objects.equals(mode, PROVIDER_MODE_SIMULATED)) { + return new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain); + } else if (Objects.equals(mode, PROVIDER_MODE_DISABLED)) { + return new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain); + } else { + // mode == PROVIDER_MODE_OVERRIDE_ENABLED (or unknown). + return createRealProxy(); + } + } + + /** Returns the mode of the provider. */ + @NonNull + private String getMode() { + if (mIndex == 0) { + return mServiceConfigAccessor.getPrimaryLocationTimeZoneProviderMode(); + } else { + return mServiceConfigAccessor.getSecondaryLocationTimeZoneProviderMode(); + } + } + + @NonNull + private RealLocationTimeZoneProviderProxy createRealProxy() { + String providerServiceAction = mServiceAction; + String providerPackageName = getPackageName(); + return new RealLocationTimeZoneProviderProxy( + mContext, mHandler, mThreadingDomain, providerServiceAction, + providerPackageName); + } + + @NonNull + private String getPackageName() { + if (mIndex == 0) { + return mServiceConfigAccessor.getPrimaryLocationTimeZoneProviderPackageName(); + } else { + return mServiceConfigAccessor.getSecondaryLocationTimeZoneProviderPackageName(); + } + } + } } diff --git a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java index bdf4a70a6a2b..a1c4028595b5 100644 --- a/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java +++ b/services/core/java/com/android/server/timezonedetector/location/LocationTimeZoneManagerShellCommand.java @@ -16,19 +16,25 @@ package com.android.server.timezonedetector.location; import static android.app.time.LocationTimeZoneManager.DUMP_STATE_OPTION_PROTO; -import static android.app.time.LocationTimeZoneManager.PRIMARY_PROVIDER_NAME; -import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DISABLED; -import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE; -import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED; -import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME; import static android.app.time.LocationTimeZoneManager.SERVICE_NAME; import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_DUMP_STATE; import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_RECORD_PROVIDER_STATES; import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND; -import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE; import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_START; import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_STOP; +import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME; +import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED; +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_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS; +import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS; +import static com.android.server.timedetector.ServerFlags.KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS; +import static com.android.server.timedetector.ServerFlags.KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE; +import static com.android.server.timedetector.ServerFlags.KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE; +import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_DISABLED; +import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_ENABLED; +import static com.android.server.timezonedetector.ServiceConfigAccessor.PROVIDER_MODE_SIMULATED; import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED; import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED; import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN; @@ -53,16 +59,12 @@ import com.android.server.timezonedetector.location.LocationTimeZoneProvider.Pro import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.Arrays; import java.util.List; import java.util.Objects; /** Implements the shell command interface for {@link LocationTimeZoneManagerService}. */ class LocationTimeZoneManagerShellCommand extends ShellCommand { - private static final List<String> VALID_PROVIDER_NAMES = - Arrays.asList(PRIMARY_PROVIDER_NAME, SECONDARY_PROVIDER_NAME); - private final LocationTimeZoneManagerService mService; LocationTimeZoneManagerShellCommand(LocationTimeZoneManagerService service) { @@ -82,9 +84,6 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand { case SHELL_COMMAND_STOP: { return runStop(); } - case SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE: { - return runSetProviderModeOverride(); - } case SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND: { return runSendProviderTestCommand(); } @@ -110,10 +109,6 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand { pw.println(" Starts the location_time_zone_manager, creating time zone providers."); pw.printf(" %s\n", SHELL_COMMAND_STOP); pw.println(" Stops the location_time_zone_manager, destroying time zone providers."); - pw.printf(" %s <provider name> <mode>\n", SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE); - pw.println(" Sets a provider into a test mode next time the service started."); - pw.printf(" Values: %s|%s|%s\n", PROVIDER_MODE_OVERRIDE_NONE, - PROVIDER_MODE_OVERRIDE_DISABLED, PROVIDER_MODE_OVERRIDE_SIMULATED); pw.printf(" %s (true|false)\n", SHELL_COMMAND_RECORD_PROVIDER_STATES); pw.printf(" Enables / disables provider state recording mode. See also %s. The default" + " state is always \"false\".\n", SHELL_COMMAND_DUMP_STATE); @@ -126,11 +121,11 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand { pw.println(" Dumps Location Time Zone Manager state for tests as text or binary proto" + " form."); pw.println(" See the LocationTimeZoneManagerServiceStateProto definition for details."); - pw.printf(" %s <provider name> <test command>\n", + pw.printf(" %s <provider index> <test command>\n", SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND); pw.println(" Passes a test command to the named provider."); pw.println(); - pw.printf("<provider name> = One of %s\n", VALID_PROVIDER_NAMES); + pw.println("<provider index> = 0 (primary), 1 (secondary)"); pw.println(); pw.printf("%s details:\n", SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND); pw.println(); @@ -146,6 +141,47 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand { pw.println(); pw.println("Test commands cannot currently be passed to real provider implementations."); pw.println(); + pw.printf("This service is also affected by the following device_config flags in the" + + " %s namespace:\n", NAMESPACE_SYSTEM_TIME); + pw.printf(" %s - [default=true], only observed if the feature is enabled in config," + + "set this to false to disable the feature\n", + KEY_LOCATION_TIME_ZONE_DETECTION_FEATURE_SUPPORTED); + pw.printf(" %s - [default=false]. Only used if the device does not have an explicit" + + " 'location time zone detection enabled' setting configured [*].\n", + KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT); + pw.printf(" %s - [default=<unset>]. Used to override the device's 'location time zone" + + " detection enabled' setting [*]\n", + KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE); + pw.printf(" %s - Overrides the mode of the primary provider. Values=%s|%s|%s\n", + KEY_PRIMARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE, + PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED, PROVIDER_MODE_SIMULATED); + pw.printf(" %s - Overrides the mode of the secondary provider. Values=%s|%s|%s\n", + KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE, + PROVIDER_MODE_DISABLED, PROVIDER_MODE_ENABLED, PROVIDER_MODE_SIMULATED); + pw.printf(" %s - \n", + KEY_SECONDARY_LOCATION_TIME_ZONE_PROVIDER_MODE_OVERRIDE); + pw.printf(" %s - Sets the amount of time the service waits when uncertain before making" + + " an 'uncertain' suggestion to the time zone detector.\n", + KEY_LOCATION_TIME_ZONE_DETECTION_UNCERTAINTY_DELAY_MILLIS); + pw.printf(" %s - Sets the initialization time passed to the location time zone providers" + + "\n", + KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_MILLIS); + pw.printf(" %s - Sets the amount of extra time added to the location time zone providers" + + " initialization time\n", + KEY_LOCATION_TIME_ZONE_PROVIDER_INITIALIZATION_TIMEOUT_FUZZ_MILLIS); + pw.println(); + pw.println("[*] The user must still have location = on / auto time zone detection = on"); + pw.println(); + pw.printf("Typically, use '%s' to stop the service before setting individual" + + " flags and '%s' after to restart it.\n", + SHELL_COMMAND_STOP, SHELL_COMMAND_START); + pw.println(); + pw.println("Example:"); + pw.printf(" $ adb shell cmd device_config put %s %s %s\n", + NAMESPACE_SYSTEM_TIME, KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, + "true"); + pw.println("See adb shell cmd device_config for more information."); + pw.println(); } private int runStart() { @@ -172,21 +208,6 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand { return 0; } - private int runSetProviderModeOverride() { - PrintWriter outPrintWriter = getOutPrintWriter(); - try { - String providerName = getNextArgRequired(); - String modeOverride = getNextArgRequired(); - outPrintWriter.println("Setting provider mode override for " + providerName - + " to " + modeOverride); - mService.setProviderModeOverride(providerName, modeOverride); - } catch (RuntimeException e) { - reportError(e); - return 1; - } - return 0; - } - private int runRecordProviderStates() { PrintWriter outPrintWriter = getOutPrintWriter(); boolean enabled; @@ -288,10 +309,10 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand { private int runSendProviderTestCommand() { PrintWriter outPrintWriter = getOutPrintWriter(); - String providerName; + int providerIndex; TestCommand testCommand; try { - providerName = validateProviderName(getNextArgRequired()); + providerIndex = parseProviderIndex(getNextArgRequired()); testCommand = createTestCommandFromNextShellArg(); } catch (RuntimeException e) { reportError(e); @@ -299,9 +320,9 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand { } outPrintWriter.println("Injecting testCommand=" + testCommand - + " to providerName=" + providerName); + + " to providerIndex=" + providerIndex); try { - Bundle result = mService.handleProviderTestCommand(providerName, testCommand); + Bundle result = mService.handleProviderTestCommand(providerIndex, testCommand); outPrintWriter.println(result); } catch (RuntimeException e) { reportError(e); @@ -321,11 +342,11 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand { e.printStackTrace(errPrintWriter); } - @NonNull - static String validateProviderName(@NonNull String value) { - if (!VALID_PROVIDER_NAMES.contains(value)) { - throw new IllegalArgumentException("Unknown provider name=" + value); + private static int parseProviderIndex(@NonNull String providerIndexString) { + int providerIndex = Integer.parseInt(providerIndexString); + if (providerIndex < 0 || providerIndex > 1) { + throw new IllegalArgumentException(providerIndexString); } - return value; + return providerIndex; } } diff --git a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java index 6c3f016588f8..b5ac712a3522 100644 --- a/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java +++ b/services/core/java/com/android/server/timezonedetector/location/RealLocationTimeZoneProviderProxy.java @@ -62,15 +62,17 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy im RealLocationTimeZoneProviderProxy( @NonNull Context context, @NonNull Handler handler, @NonNull ThreadingDomain threadingDomain, @NonNull String action, - int enableOverlayResId, int nonOverlayPackageResId) { + @NonNull String providerPackageName) { super(context, threadingDomain); mManagerProxy = null; mRequest = TimeZoneProviderRequest.createStopUpdatesRequest(); + + Objects.requireNonNull(providerPackageName); mServiceWatcher = ServiceWatcher.create(context, handler, "RealLocationTimeZoneProviderProxy", - new CurrentUserServiceSupplier(context, action, enableOverlayResId, - nonOverlayPackageResId, BIND_TIME_ZONE_PROVIDER_SERVICE, + new CurrentUserServiceSupplier(context, action, + providerPackageName, BIND_TIME_ZONE_PROVIDER_SERVICE, INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE), this); } |