blob: f054c5756e20ac50aea03d98959ff0fb0efd7e86 [file] [log] [blame]
/*
* 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 static com.android.server.timezonedetector.location.LocationTimeZoneManagerService.debugLog;
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;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_UNCERTAIN;
import static com.android.server.timezonedetector.location.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STOPPED;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.RemoteCallback;
import android.util.IndentingPrintWriter;
import java.time.Duration;
import java.util.Objects;
/**
* The real, system-server side implementation of a binder call backed {@link
* LocationTimeZoneProvider}. It handles keeping track of current state, timeouts and ensuring
* events are passed to the {@link LocationTimeZoneProviderController} on the required thread.
*/
class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider {
@NonNull private final LocationTimeZoneProviderProxy mProxy;
BinderLocationTimeZoneProvider(
@NonNull ProviderMetricsLogger providerMetricsLogger,
@NonNull ThreadingDomain threadingDomain,
@NonNull String providerName,
@NonNull LocationTimeZoneProviderProxy proxy) {
super(providerMetricsLogger, threadingDomain, providerName,
new ZoneInfoDbTimeZoneProviderEventPreProcessor());
mProxy = Objects.requireNonNull(proxy);
}
@Override
void onInitialize() {
mProxy.initialize(new LocationTimeZoneProviderProxy.Listener() {
@Override
public void onReportTimeZoneProviderEvent(
@NonNull TimeZoneProviderEvent timeZoneProviderEvent) {
handleTimeZoneProviderEvent(timeZoneProviderEvent);
}
@Override
public void onProviderBound() {
handleOnProviderBound();
}
@Override
public void onProviderUnbound() {
handleProviderLost("onProviderUnbound()");
}
});
}
@Override
void onDestroy() {
mProxy.destroy();
}
private void handleProviderLost(String reason) {
mThreadingDomain.assertCurrentThread();
synchronized (mSharedLock) {
ProviderState currentState = mCurrentState.get();
switch (currentState.stateEnum) {
case PROVIDER_STATE_STARTED_INITIALIZING:
case PROVIDER_STATE_STARTED_UNCERTAIN:
case PROVIDER_STATE_STARTED_CERTAIN: {
// Losing a remote provider is treated as becoming uncertain.
String msg = "handleProviderLost reason=" + reason
+ ", mProviderName=" + mProviderName
+ ", currentState=" + currentState;
debugLog(msg);
// This is an unusual PROVIDER_STATE_STARTED_UNCERTAIN state because
// event == null
ProviderState newState = currentState.newState(
PROVIDER_STATE_STARTED_UNCERTAIN, null,
currentState.currentUserConfiguration, msg);
setCurrentState(newState, true);
break;
}
case PROVIDER_STATE_STOPPED: {
debugLog("handleProviderLost reason=" + reason
+ ", mProviderName=" + mProviderName
+ ", currentState=" + currentState
+ ": No state change required, provider is stopped.");
break;
}
case PROVIDER_STATE_PERM_FAILED:
case PROVIDER_STATE_DESTROYED: {
debugLog("handleProviderLost reason=" + reason
+ ", mProviderName=" + mProviderName
+ ", currentState=" + currentState
+ ": No state change required, provider is terminated.");
break;
}
default: {
throw new IllegalStateException("Unknown currentState=" + currentState);
}
}
}
}
private void handleOnProviderBound() {
mThreadingDomain.assertCurrentThread();
synchronized (mSharedLock) {
ProviderState currentState = mCurrentState.get();
switch (currentState.stateEnum) {
case PROVIDER_STATE_STARTED_INITIALIZING:
case PROVIDER_STATE_STARTED_CERTAIN:
case PROVIDER_STATE_STARTED_UNCERTAIN: {
debugLog("handleOnProviderBound mProviderName=" + mProviderName
+ ", currentState=" + currentState + ": Provider is started.");
break;
}
case PROVIDER_STATE_STOPPED: {
debugLog("handleOnProviderBound mProviderName=" + mProviderName
+ ", currentState=" + currentState + ": Provider is stopped.");
break;
}
case PROVIDER_STATE_PERM_FAILED:
case PROVIDER_STATE_DESTROYED: {
debugLog("handleOnProviderBound"
+ ", mProviderName=" + mProviderName
+ ", currentState=" + currentState
+ ": No state change required, provider is terminated.");
break;
}
default: {
throw new IllegalStateException("Unknown currentState=" + currentState);
}
}
}
}
@Override
void onStartUpdates(@NonNull Duration initializationTimeout) {
// Set a request on the proxy - it will be sent immediately if the service is bound,
// or will be sent as soon as the service becomes bound.
TimeZoneProviderRequest request =
TimeZoneProviderRequest.createStartUpdatesRequest(initializationTimeout);
mProxy.setRequest(request);
}
@Override
void onStopUpdates() {
TimeZoneProviderRequest request = TimeZoneProviderRequest.createStopUpdatesRequest();
mProxy.setRequest(request);
}
/**
* Passes the supplied test command to the current proxy.
*/
@Override
void handleTestCommand(@NonNull TestCommand testCommand, @Nullable RemoteCallback callback) {
mThreadingDomain.assertCurrentThread();
mProxy.handleTestCommand(testCommand, callback);
}
@Override
public void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
synchronized (mSharedLock) {
ipw.println("{BinderLocationTimeZoneProvider}");
ipw.println("mProviderName=" + mProviderName);
ipw.println("mCurrentState=" + mCurrentState);
ipw.println("mProxy=" + mProxy);
ipw.println("State history:");
ipw.increaseIndent();
mCurrentState.dump(ipw);
ipw.decreaseIndent();
ipw.println("Proxy details:");
ipw.increaseIndent();
mProxy.dump(ipw, args);
ipw.decreaseIndent();
}
}
@Override
public String toString() {
synchronized (mSharedLock) {
return "BinderLocationTimeZoneProvider{"
+ "mProviderName=" + mProviderName
+ ", mCurrentState=" + mCurrentState
+ ", mProxy=" + mProxy
+ '}';
}
}
}