Merge "Fix behavior when primary fails initialization"

This commit is contained in:
Neil Fuller
2021-01-11 18:02:33 +00:00
committed by Android (Google) Code Review
2 changed files with 98 additions and 0 deletions

View File

@@ -73,6 +73,10 @@ class ControllerImpl extends LocationTimeZoneProviderController {
// Non-null after initialize()
private Callback mCallback;
/** Indicates both providers have completed initialization. */
@GuardedBy("mSharedLock")
private boolean mProvidersInitialized;
/**
* Used for scheduling uncertainty timeouts, i.e after a provider has reported uncertainty.
* This timeout is not provider-specific: it is started when the controller becomes uncertain
@@ -108,6 +112,7 @@ class ControllerImpl extends LocationTimeZoneProviderController {
ControllerImpl.this::onProviderStateChange;
mPrimaryProvider.initialize(providerListener);
mSecondaryProvider.initialize(providerListener);
mProvidersInitialized = true;
alterProvidersStartedStateIfRequired(
null /* oldConfiguration */, mCurrentUserConfiguration);
@@ -322,6 +327,16 @@ class ControllerImpl extends LocationTimeZoneProviderController {
assertProviderKnown(provider);
synchronized (mSharedLock) {
// Ignore provider state changes during initialization. e.g. if the primary provider
// moves to PROVIDER_STATE_PERM_FAILED during initialization, the secondary will not
// be ready to take over yet.
if (!mProvidersInitialized) {
warnLog("onProviderStateChange: Ignoring provider state change because both"
+ " providers have not yet completed initialization."
+ " providerState=" + providerState);
return;
}
switch (providerState.stateEnum) {
case PROVIDER_STATE_STARTED_INITIALIZING:
case PROVIDER_STATE_STOPPED:

View File

@@ -88,6 +88,81 @@ public class ControllerImplTest {
new TestLocationTimeZoneProvider(mTestThreadingDomain, "secondary");
}
@Test
public void initializationFailure_primary() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
Duration expectedInitTimeout = testEnvironment.getProviderInitializationTimeout()
.plus(testEnvironment.getProviderInitializationTimeoutFuzz());
mTestPrimaryLocationTimeZoneProvider.setFailDuringInitialization(true);
// Initialize. After initialization the providers must be initialized and one should be
// started.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertInitialized();
mTestSecondaryLocationTimeZoneProvider.assertInitialized();
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestSecondaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void initializationFailure_secondary() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
Duration expectedInitTimeout = testEnvironment.getProviderInitializationTimeout()
.plus(testEnvironment.getProviderInitializationTimeoutFuzz());
mTestSecondaryLocationTimeZoneProvider.setFailDuringInitialization(true);
// Initialize. After initialization the providers must be initialized and one should be
// started.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertInitialized();
mTestSecondaryLocationTimeZoneProvider.assertInitialized();
mTestPrimaryLocationTimeZoneProvider.assertStateEnumAndConfigAndCommit(
PROVIDER_STATE_STARTED_INITIALIZING, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestPrimaryLocationTimeZoneProvider.assertInitializationTimeoutSet(expectedInitTimeout);
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertNoSuggestionMade();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void initializationFailure_both() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
TestEnvironment testEnvironment = new TestEnvironment(
mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
mTestPrimaryLocationTimeZoneProvider.setFailDuringInitialization(true);
mTestSecondaryLocationTimeZoneProvider.setFailDuringInitialization(true);
// Initialize. After initialization the providers must be initialized and one should be
// started.
controllerImpl.initialize(testEnvironment, mTestCallback);
mTestPrimaryLocationTimeZoneProvider.assertInitialized();
mTestSecondaryLocationTimeZoneProvider.assertInitialized();
mTestPrimaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestSecondaryLocationTimeZoneProvider.assertIsPermFailedAndCommit();
mTestCallback.assertUncertainSuggestionMadeAndCommit();
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
@Test
public void initialState_started() {
ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
@@ -1097,6 +1172,7 @@ public class ControllerImplTest {
/** Used to track historic provider states for tests. */
private final TestState<ProviderState> mTestProviderState = new TestState<>();
private boolean mFailDuringInitialization;
private boolean mInitialized;
private boolean mDestroyed;
@@ -1107,9 +1183,16 @@ public class ControllerImplTest {
super(threadingDomain, providerName);
}
public void setFailDuringInitialization(boolean failInitialization) {
mFailDuringInitialization = failInitialization;
}
@Override
void onInitialize() {
mInitialized = true;
if (mFailDuringInitialization) {
throw new RuntimeException("Simulated initialization failure");
}
}
@Override