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

Commit 020a6ef4 authored by Neil Fuller's avatar Neil Fuller Committed by Android (Google) Code Review
Browse files

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

parents f0bff1b9 b2837a16
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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
+86 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 * 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.
@@ -18,57 +18,69 @@ 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;

import java.time.Duration;

/**
 * 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.
 * 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>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.
 * <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 NullLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
class DisabledLocationTimeZoneProvider extends LocationTimeZoneProvider {

    /** Creates the instance. */
    NullLocationTimeZoneProviderProxy(
            @NonNull Context context, @NonNull ThreadingDomain threadingDomain) {
        super(context, threadingDomain);
    DisabledLocationTimeZoneProvider(
            @NonNull ProviderMetricsLogger providerMetricsLogger,
            @NonNull ThreadingDomain threadingDomain,
            @NonNull String providerName,
            boolean recordStateChanges) {
        super(providerMetricsLogger, threadingDomain, providerName, x -> x, recordStateChanges);
    }

    @Override
    void onInitialize() {
        // No-op
    boolean onInitialize() {
        // Fail initialization, preventing further use.
        return false;
    }

    @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);
    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("{NullLocationTimeZoneProviderProxy}");
            ipw.println("{DisabledLocationTimeZoneProvider}");
            ipw.println("mProviderName=" + mProviderName);
            ipw.println("mCurrentState=" + mCurrentState);
        }
    }

    @Override
    public String toString() {
        synchronized (mSharedLock) {
            return "DisabledLocationTimeZoneProvider{"
                    + "mProviderName=" + mProviderName
                    + ", mCurrentState=" + mCurrentState
                    + '}';
        }
    }
}
+12 −16
Original line number Diff line number Diff line
@@ -447,12 +447,19 @@ public class LocationTimeZoneManagerService extends Binder {

        @NonNull
        LocationTimeZoneProvider createProvider() {
            LocationTimeZoneProviderProxy proxy = createProxy();
            ProviderMetricsLogger providerMetricsLogger = new RealProviderMetricsLogger(mIndex);

            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
        public void dump(IndentingPrintWriter ipw, String[] args) {
@@ -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();
+15 −4
Original line number Diff line number Diff line
@@ -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
+2 −4
Original line number Diff line number Diff line
@@ -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
Loading