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

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

Merge "Refactoring: Support alt. network time source"

parents 65fe242a 8ad07e27
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -240,7 +240,11 @@ public final class GnssCapabilities implements Parcelable {
    }

    /**
     * Returns {@code true} if GNSS chipset supports on demand time, {@code false} otherwise.
     * Returns {@code true} if GNSS chipset requests periodic time signal injection from the
     * platform in addition to on-demand and occasional time updates, {@code false} otherwise.
     *
     * <p><em>Note: The naming of this capability and the behavior it controls differ substantially.
     * This is the result of a historic implementation bug, b/73893222.</em>
     */
    public boolean hasOnDemandTime() {
        return (mTopFlags & TOP_HAL_CAPABILITY_ON_DEMAND_TIME) != 0;
+25 −18
Original line number Diff line number Diff line
@@ -113,9 +113,8 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.HexDump;
import com.android.server.FgThread;
import com.android.server.location.gnss.GnssSatelliteBlocklistHelper.GnssSatelliteBlocklistCallback;
import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback;
import com.android.server.location.gnss.NetworkTimeHelper.InjectTimeCallback;
import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.injector.Injector;
import com.android.server.location.provider.AbstractLocationProvider;

import java.io.FileDescriptor;
@@ -138,7 +137,7 @@ import java.util.concurrent.TimeUnit;
 * {@hide}
 */
public class GnssLocationProvider extends AbstractLocationProvider implements
        InjectNtpTimeCallback, GnssSatelliteBlocklistCallback, GnssNative.BaseCallbacks,
        InjectTimeCallback, GnssSatelliteBlocklistCallback, GnssNative.BaseCallbacks,
        GnssNative.LocationCallbacks, GnssNative.SvStatusCallbacks, GnssNative.AGpsCallbacks,
        GnssNative.PsdsCallbacks, GnssNative.NotificationCallbacks,
        GnssNative.LocationRequestCallbacks, GnssNative.TimeCallbacks {
@@ -307,7 +306,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
    private boolean mSuplEsEnabled = false;

    private final LocationExtras mLocationExtras = new LocationExtras();
    private final NtpTimeHelper mNtpTimeHelper;
    private final NetworkTimeHelper mNetworkTimeHelper;
    private final GnssSatelliteBlocklistHelper mGnssSatelliteBlocklistHelper;

    // Available only on GNSS HAL 2.0 implementations and later.
@@ -398,7 +397,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
        }
    }

    public GnssLocationProvider(Context context, Injector injector, GnssNative gnssNative,
    public GnssLocationProvider(Context context, GnssNative gnssNative,
            GnssMetrics gnssMetrics) {
        super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES,
                Collections.emptySet());
@@ -470,7 +469,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
                GnssLocationProvider.this::onNetworkAvailable,
                mHandler.getLooper(), mNIHandler);

        mNtpTimeHelper = new NtpTimeHelper(mContext, mHandler.getLooper(), this);
        mNetworkTimeHelper = NetworkTimeHelper.create(mContext, mHandler.getLooper(), this);
        mGnssSatelliteBlocklistHelper =
                new GnssSatelliteBlocklistHelper(mContext,
                        mHandler.getLooper(), this);
@@ -647,18 +646,19 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
    }

    /**
     * Implements {@link InjectNtpTimeCallback#injectTime}
     * Implements {@link InjectTimeCallback#injectTime}
     */
    @Override
    public void injectTime(long time, long timeReference, int uncertainty) {
        mGnssNative.injectTime(time, timeReference, uncertainty);
    public void injectTime(long unixEpochTimeMillis, long elapsedRealtimeMillis,
            int uncertaintyMillis) {
        mGnssNative.injectTime(unixEpochTimeMillis, elapsedRealtimeMillis, uncertaintyMillis);
    }

    /**
     * Implements {@link GnssNetworkConnectivityHandler.GnssNetworkListener#onNetworkAvailable()}
     */
    private void onNetworkAvailable() {
        mNtpTimeHelper.onNetworkAvailable();
        mNetworkTimeHelper.onNetworkAvailable();
        // Download only if supported, (prevents an unnecessary on-boot download)
        if (mSupportsPsds) {
            synchronized (mLock) {
@@ -1145,7 +1145,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
        if ("delete_aiding_data".equals(command)) {
            deleteAidingData(extras);
        } else if ("force_time_injection".equals(command)) {
            requestUtcTime();
            demandUtcTimeInjection();
        } else if ("force_psds_injection".equals(command)) {
            if (mSupportsPsds) {
                postWithWakeLockHeld(() -> handleDownloadPsdsData(
@@ -1514,9 +1514,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
                /* userResponse= */ 0);
    }

    private void requestUtcTime() {
        if (DEBUG) Log.d(TAG, "utcTimeRequest");
        postWithWakeLockHeld(mNtpTimeHelper::retrieveAndInjectNtpTime);
    private void demandUtcTimeInjection() {
        if (DEBUG) Log.d(TAG, "demandUtcTimeInjection");
        postWithWakeLockHeld(mNetworkTimeHelper::demandUtcTimeInjection);
    }


@@ -1721,9 +1721,16 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
    public void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
            GnssCapabilities newCapabilities) {
        mHandler.post(() -> {
            if (mGnssNative.getCapabilities().hasOnDemandTime()) {
                mNtpTimeHelper.enablePeriodicTimeInjection();
                requestUtcTime();
            boolean useOnDemandTimeInjection = mGnssNative.getCapabilities().hasOnDemandTime();

            // b/73893222: There is a historic bug on Android, which means that the capability
            // "on demand time" is interpreted as "enable periodic injection" elsewhere but an
            // on-demand injection is done here. GNSS developers may have come to rely on the
            // periodic behavior, so it has been kept and all methods named to reflect what is
            // actually done. "On demand" requests are supported regardless of the capability.
            mNetworkTimeHelper.setPeriodicTimeInjectionMode(useOnDemandTimeInjection);
            if (useOnDemandTimeInjection) {
                demandUtcTimeInjection();
            }

            restartLocationRequest();
@@ -1857,7 +1864,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements

    @Override
    public void onRequestUtcTime() {
        requestUtcTime();
        demandUtcTimeInjection();
    }

    @Override
+1 −2
Original line number Diff line number Diff line
@@ -83,8 +83,7 @@ public class GnssManagerService {
        mGnssMetrics = new GnssMetrics(mContext, IBatteryStats.Stub.asInterface(
                ServiceManager.getService(BatteryStats.SERVICE_NAME)), mGnssNative);

        mGnssLocationProvider = new GnssLocationProvider(mContext, injector, mGnssNative,
                mGnssMetrics);
        mGnssLocationProvider = new GnssLocationProvider(mContext, mGnssNative, mGnssMetrics);
        mGnssStatusProvider = new GnssStatusProvider(injector, mGnssNative);
        mGnssNmeaProvider = new GnssNmeaProvider(injector, mGnssNative);
        mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector, mGnssNative);
+75 −0
Original line number Diff line number Diff line
/*
 * 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.location.gnss;

import android.content.Context;
import android.os.Looper;

/**
 * An abstraction for use by {@link GnssLocationProvider}. This class allows switching between
 * implementations with a compile-time constant change, which is less risky than rolling back a
 * whole class. When there is a single implementation again this class can be replaced by that
 * implementation.
 */
abstract class NetworkTimeHelper {

    /**
     * The callback interface used by {@link NetworkTimeHelper} to report the time to {@link
     * GnssLocationProvider}. The callback can happen at any time using the thread associated with
     * the looper passed to {@link #create(Context, Looper, InjectTimeCallback)}.
     */
    interface InjectTimeCallback {
        void injectTime(long unixEpochTimeMillis, long elapsedRealtimeMillis,
                int uncertaintyMillis);
    }

    /**
     * Creates the {@link NetworkTimeHelper} instance for use by {@link GnssLocationProvider}.
     */
    static NetworkTimeHelper create(
            Context context, Looper looper, InjectTimeCallback injectTimeCallback) {
        return new NtpNetworkTimeHelper(context, looper, injectTimeCallback);
    }

    /**
     * Sets the "on demand time injection" mode.
     *
     * <p>Called by {@link GnssLocationProvider} to set the expected time injection behavior.
     * When {@code enablePeriodicTimeInjection == true}, the time helper should periodically send
     * the time on an undefined schedule. The time can be injected at other times for other reasons
     * as well as be requested via {@link #demandUtcTimeInjection()}.
     *
     * @param periodicTimeInjectionEnabled {@code true} if the GNSS implementation requires periodic
     *   time signals
     */
    abstract void setPeriodicTimeInjectionMode(boolean periodicTimeInjectionEnabled);

    /**
     * Requests an asynchronous time injection via {@link InjectTimeCallback#injectTime}, if a
     * network time is available. {@link InjectTimeCallback#injectTime} may not be called if a
     * network time is not available.
     */
    abstract void demandUtcTimeInjection();

    /**
     * Notifies that network connectivity has been established.
     *
     * <p>Called by {@link GnssLocationProvider} when the device establishes a data network
     * connection.
     */
    abstract void onNetworkAvailable();

}
+26 −27
Original line number Diff line number Diff line
@@ -30,14 +30,11 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

/**
 * Handles inject NTP time to GNSS.
 *
 * <p>The client is responsible to call {@link #onNetworkAvailable()} when network is available
 * for retrieving NTP Time.
 * Handles injecting network time to GNSS by explicitly making NTP requests when needed.
 */
class NtpTimeHelper {
class NtpNetworkTimeHelper extends NetworkTimeHelper {

    private static final String TAG = "NtpTimeHelper";
    private static final String TAG = "NtpNetworkTimeHelper";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    // states for injecting ntp
@@ -71,23 +68,19 @@ class NtpTimeHelper {
    private final WakeLock mWakeLock;
    private final Handler mHandler;

    private final InjectNtpTimeCallback mCallback;
    private final InjectTimeCallback mCallback;

    // flags to trigger NTP when network becomes available
    // initialized to STATE_PENDING_NETWORK so we do NTP when the network comes up after booting
    @GuardedBy("this")
    private int mInjectNtpTimeState = STATE_PENDING_NETWORK;

    // set to true if the GPS engine requested on-demand NTP time requests
    // Enables periodic time injection in addition to injection for other reasons.
    @GuardedBy("this")
    private boolean mOnDemandTimeInjection;

    interface InjectNtpTimeCallback {
        void injectTime(long time, long timeReference, int uncertainty);
    }
    private boolean mPeriodicTimeInjection;

    @VisibleForTesting
    NtpTimeHelper(Context context, Looper looper, InjectNtpTimeCallback callback,
    NtpNetworkTimeHelper(Context context, Looper looper, InjectTimeCallback callback,
            NtpTrustedTime ntpTime) {
        mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        mCallback = callback;
@@ -97,14 +90,23 @@ class NtpTimeHelper {
        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
    }

    NtpTimeHelper(Context context, Looper looper, InjectNtpTimeCallback callback) {
    NtpNetworkTimeHelper(Context context, Looper looper, InjectTimeCallback callback) {
        this(context, looper, callback, NtpTrustedTime.getInstance(context));
    }

    synchronized void enablePeriodicTimeInjection() {
        mOnDemandTimeInjection = true;
    @Override
    synchronized void setPeriodicTimeInjectionMode(boolean periodicTimeInjectionEnabled) {
        if (periodicTimeInjectionEnabled) {
            mPeriodicTimeInjection = true;
        }
    }

    @Override
    void demandUtcTimeInjection() {
        retrieveAndInjectNtpTime();
    }

    @Override
    synchronized void onNetworkAvailable() {
        if (mInjectNtpTimeState == STATE_PENDING_NETWORK) {
            retrieveAndInjectNtpTime();
@@ -120,7 +122,7 @@ class NtpTimeHelper {
        return activeNetworkInfo != null && activeNetworkInfo.isConnected();
    }

    synchronized void retrieveAndInjectNtpTime() {
    private synchronized void retrieveAndInjectNtpTime() {
        if (mInjectNtpTimeState == STATE_RETRIEVING_AND_INJECTING) {
            // already downloading data
            return;
@@ -166,18 +168,15 @@ class NtpTimeHelper {

            if (DEBUG) {
                Log.d(TAG, String.format(
                        "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
                        mOnDemandTimeInjection,
                        "mPeriodicTimeInjection=%s, refreshSuccess=%s, delay=%s",
                        mPeriodicTimeInjection,
                        refreshSuccess,
                        delay));
            }
            // TODO(b/73893222): reconcile Capabilities bit 'on demand' name vs. de facto periodic
            // injection.
            if (mOnDemandTimeInjection || !refreshSuccess) {
                /* Schedule next NTP injection.
                 * Since this is delayed, the wake lock is released right away, and will be held
                 * again when the delayed task runs.
                 */
            if (mPeriodicTimeInjection || !refreshSuccess) {
                // Schedule next NTP injection.
                // Since this is delayed, the wake lock is released right away, and will be held
                // again when the delayed task runs.
                mHandler.postDelayed(this::retrieveAndInjectNtpTime, delay);
            }
        }
Loading