Merge "Enable providers to report they are "missing""

This commit is contained in:
Neil Fuller
2022-11-17 10:12:54 +00:00
committed by Android (Google) Code Review
7 changed files with 119 additions and 100 deletions

View File

@@ -53,7 +53,7 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider {
}
@Override
void onInitialize() {
boolean onInitialize() {
mProxy.initialize(new LocationTimeZoneProviderProxy.Listener() {
@Override
public void onReportTimeZoneProviderEvent(
@@ -71,6 +71,7 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider {
handleTemporaryFailure("onProviderUnbound()");
}
});
return true;
}
@Override

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2022 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.timezonedetector.location;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.IndentingPrintWriter;
import java.time.Duration;
/**
* A {@link LocationTimeZoneProvider} that provides minimal responses needed to operate correctly
* when there is no "real" provider configured / enabled. This is used when the platform supports
* more providers than are needed for an Android deployment.
*
* <p>That is, the {@link LocationTimeZoneProviderController} supports a primary and a secondary
* {@link LocationTimeZoneProvider}, but if only a primary is configured, the secondary provider
* config will marked as "disabled" and the {@link LocationTimeZoneProvider} implementation will use
* {@link DisabledLocationTimeZoneProvider}. The {@link DisabledLocationTimeZoneProvider} fails
* initialization and immediately moves to a "permanent failure" state, which ensures the {@link
* LocationTimeZoneProviderController} correctly categorizes it and won't attempt to use it.
*/
class DisabledLocationTimeZoneProvider extends LocationTimeZoneProvider {
DisabledLocationTimeZoneProvider(
@NonNull ProviderMetricsLogger providerMetricsLogger,
@NonNull ThreadingDomain threadingDomain,
@NonNull String providerName,
boolean recordStateChanges) {
super(providerMetricsLogger, threadingDomain, providerName, x -> x, recordStateChanges);
}
@Override
boolean onInitialize() {
// Fail initialization, preventing further use.
return false;
}
@Override
void onDestroy() {
}
@Override
void onStartUpdates(@NonNull Duration initializationTimeout,
@NonNull Duration eventFilteringAgeThreshold) {
throw new UnsupportedOperationException("Provider is disabled");
}
@Override
void onStopUpdates() {
throw new UnsupportedOperationException("Provider is disabled");
}
@Override
public void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
synchronized (mSharedLock) {
ipw.println("{DisabledLocationTimeZoneProvider}");
ipw.println("mProviderName=" + mProviderName);
ipw.println("mCurrentState=" + mCurrentState);
}
}
@Override
public String toString() {
synchronized (mSharedLock) {
return "DisabledLocationTimeZoneProvider{"
+ "mProviderName=" + mProviderName
+ ", mCurrentState=" + mCurrentState
+ '}';
}
}
}

View File

@@ -447,11 +447,18 @@ public class LocationTimeZoneManagerService extends Binder {
@NonNull
LocationTimeZoneProvider createProvider() {
LocationTimeZoneProviderProxy proxy = createProxy();
ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(mIndex);
return new BinderLocationTimeZoneProvider(
providerMetricsLogger, mThreadingDomain, mName, proxy,
mServiceConfigAccessor.getRecordStateChangesForTests());
String mode = getMode();
if (Objects.equals(mode, PROVIDER_MODE_DISABLED)) {
return new DisabledLocationTimeZoneProvider(providerMetricsLogger, mThreadingDomain,
mName, mServiceConfigAccessor.getRecordStateChangesForTests());
} else {
LocationTimeZoneProviderProxy proxy = createBinderProxy();
return new BinderLocationTimeZoneProvider(
providerMetricsLogger, mThreadingDomain, mName, proxy,
mServiceConfigAccessor.getRecordStateChangesForTests());
}
}
@Override
@@ -460,17 +467,6 @@ public class LocationTimeZoneManagerService extends Binder {
ipw.printf("getPackageName()=%s\n", getPackageName());
}
@NonNull
private LocationTimeZoneProviderProxy createProxy() {
String mode = getMode();
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 (enabled/disabled). */
@NonNull
private String getMode() {
@@ -482,7 +478,7 @@ public class LocationTimeZoneManagerService extends Binder {
}
@NonNull
private RealLocationTimeZoneProviderProxy createRealProxy() {
private RealLocationTimeZoneProviderProxy createBinderProxy() {
String providerServiceAction = mServiceAction;
boolean isTestProvider = isTestProvider();
String providerPackageName = getPackageName();

View File

@@ -448,13 +448,21 @@ abstract class LocationTimeZoneProvider implements Dumpable {
currentState = currentState.newState(PROVIDER_STATE_STOPPED, null, null, "initialize");
setCurrentState(currentState, false);
boolean initializationSuccess;
String initializationFailureReason;
// Guard against uncaught exceptions due to initialization problems.
try {
onInitialize();
initializationSuccess = onInitialize();
initializationFailureReason = "onInitialize() returned false";
} catch (RuntimeException e) {
warnLog("Unable to initialize the provider", e);
warnLog("Unable to initialize the provider due to exception", e);
initializationSuccess = false;
initializationFailureReason = "onInitialize() threw exception:" + e.getMessage();
}
if (!initializationSuccess) {
currentState = currentState.newState(PROVIDER_STATE_PERM_FAILED, null, null,
"Failed to initialize: " + e.getMessage());
"Failed to initialize: " + initializationFailureReason);
setCurrentState(currentState, true);
}
}
@@ -462,9 +470,12 @@ abstract class LocationTimeZoneProvider implements Dumpable {
/**
* Implemented by subclasses to do work during {@link #initialize}.
*
* @return returns {@code true} on success, {@code false} if the provider should be considered
* "permanently failed" / disabled
*/
@GuardedBy("mSharedLock")
abstract void onInitialize();
abstract boolean onInitialize();
/**
* Destroys the provider. Called after the provider is stopped. This instance will not be called

View File

@@ -1,74 +0,0 @@
/*
* Copyright (C) 2020 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.timezonedetector.location;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.SystemClock;
import android.service.timezone.TimeZoneProviderEvent;
import android.util.IndentingPrintWriter;
/**
* A {@link LocationTimeZoneProviderProxy} that provides minimal responses needed for the {@link
* BinderLocationTimeZoneProvider} to operate correctly when there is no "real" provider
* configured / enabled. This can be used during development / testing, or in a production build
* when the platform supports more providers than are needed for an Android deployment.
*
* <p>For example, if the {@link LocationTimeZoneProviderController} supports a primary
* and a secondary {@link LocationTimeZoneProvider}, but only a primary is configured, the secondary
* config will be left null and the {@link LocationTimeZoneProviderProxy} implementation will be
* defaulted to a {@link NullLocationTimeZoneProviderProxy}. The {@link
* NullLocationTimeZoneProviderProxy} sends a "permanent failure" event immediately after being
* started for the first time, which ensures the {@link LocationTimeZoneProviderController} won't
* expect any further {@link TimeZoneProviderEvent}s to come from it, and won't attempt to use it
* again.
*/
class NullLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
/** Creates the instance. */
NullLocationTimeZoneProviderProxy(
@NonNull Context context, @NonNull ThreadingDomain threadingDomain) {
super(context, threadingDomain);
}
@Override
void onInitialize() {
// No-op
}
@Override
void onDestroy() {
// No-op
}
@Override
void setRequest(@NonNull TimeZoneProviderRequest request) {
if (request.sendUpdates()) {
TimeZoneProviderEvent event = TimeZoneProviderEvent.createPermanentFailureEvent(
SystemClock.elapsedRealtime(), "Provider is disabled");
handleTimeZoneProviderEvent(event);
}
}
@Override
public void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
synchronized (mSharedLock) {
ipw.println("{NullLocationTimeZoneProviderProxy}");
}
}
}

View File

@@ -1672,11 +1672,9 @@ public class LocationTimeZoneProviderControllerTest {
}
@Override
void onInitialize() {
boolean onInitialize() {
mInitialized = true;
if (mFailDuringInitialization) {
throw new RuntimeException("Simulated initialization failure");
}
return !mFailDuringInitialization;
}
@Override

View File

@@ -330,8 +330,9 @@ public class LocationTimeZoneProviderTest {
}
@Override
void onInitialize() {
boolean onInitialize() {
mOnInitializeCalled = true;
return true;
}
@Override