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

Commit 519694b5 authored by Yu-Han Yang's avatar Yu-Han Yang
Browse files

Add fullTracking to registerGnssMeasurementsCallback (implementation)

- Currently enableFullTracking has a toggle in Developer Option.
This change adds a system API for the same functionality.
- If at least one of <enableFullTracking in Developer Option> and
<enableFullTracking from the system API> is true, full tracking is
enabled when registering a GnssMeasurement callback.
- For multiple GnssMeasurement callbacks, full tracking is enabled
if *at least* one callback has fullTracking enabled. Removing a callback
might trigger restarting the measurement collection if the aggregated
requirement has changed.

Bug: 147387008

Test: atest GnssMeasurementsProviderTest
      atest GnssManagerServiceTest
      atest GnssMeasurementRegistrationTest

Change-Id: Iedf03edd7053aa0089cfea0d5c0357322f68d9c4
parent 729082ca
Loading
Loading
Loading
Loading
+101 −28
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.util.ArrayMap;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;

import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

@@ -35,26 +36,34 @@ import java.util.function.Consumer;
 *
 * @hide
 */
abstract class AbstractListenerManager<T> {
abstract class AbstractListenerManager<TRequest, TListener> {

    private static class Registration<T> {
    private static class Registration<TRequest, TListener> {
        private final Executor mExecutor;
        @Nullable private volatile T mListener;
        @Nullable private TRequest mRequest;
        @Nullable private volatile TListener mListener;

        private Registration(Executor executor, T listener) {
        private Registration(@Nullable TRequest request, Executor executor, TListener listener) {
            Preconditions.checkArgument(listener != null, "invalid null listener/callback");
            Preconditions.checkArgument(executor != null, "invalid null executor");
            mExecutor = executor;
            mListener = listener;
            mRequest = request;
        }

        @Nullable
        public TRequest getRequest() {
            return mRequest;
        }

        private void unregister() {
            mRequest = null;
            mListener = null;
        }

        private void execute(Consumer<T> operation) {
        private void execute(Consumer<TListener> operation) {
            mExecutor.execute(() -> {
                T listener = mListener;
                TListener listener = mListener;
                if (listener == null) {
                    return;
                }
@@ -71,71 +80,135 @@ abstract class AbstractListenerManager<T> {
    }

    @GuardedBy("mListeners")
    private final ArrayMap<Object, Registration<T>> mListeners = new ArrayMap<>();
    private final ArrayMap<Object, Registration<TRequest, TListener>> mListeners =
            new ArrayMap<>();

    public boolean addListener(@NonNull T listener, @NonNull Handler handler)
    @GuardedBy("mListeners")
    @Nullable
    private TRequest mMergedRequest;

    public boolean addListener(@NonNull TListener listener, @NonNull Handler handler)
            throws RemoteException {
        return addInternal(listener, handler);
        return addInternal(/* request= */ null, listener, handler);
    }

    public boolean addListener(@NonNull T listener, @NonNull Executor executor)
    public boolean addListener(@NonNull TListener listener, @NonNull Executor executor)
            throws RemoteException {
        return addInternal(listener, executor);
        return addInternal(/* request= */ null, listener, executor);
    }

    protected final boolean addInternal(@NonNull Object listener, @NonNull Handler handler)
            throws RemoteException {
        return addInternal(listener, new HandlerExecutor(handler));
    public boolean addListener(@Nullable TRequest request, @NonNull TListener listener,
            @NonNull Handler handler) throws RemoteException {
        return addInternal(request, listener, handler);
    }

    public boolean addListener(@Nullable TRequest request, @NonNull TListener listener,
            @NonNull Executor executor) throws RemoteException {
        return addInternal(request, listener, executor);
    }

    protected final boolean addInternal(@Nullable TRequest request, @NonNull Object listener,
            @NonNull Handler handler) throws RemoteException {
        return addInternal(request, listener, new HandlerExecutor(handler));
    }

    protected final boolean addInternal(@NonNull Object listener, @NonNull Executor executor)
    protected final boolean addInternal(@Nullable TRequest request, @NonNull Object listener,
            @NonNull Executor executor)
            throws RemoteException {
        Preconditions.checkArgument(listener != null, "invalid null listener/callback");
        return addInternal(listener, new Registration<>(executor, convertKey(listener)));
        return addInternal(listener, new Registration<>(request, executor, convertKey(listener)));
    }

    private boolean addInternal(Object key, Registration<T> registration) throws RemoteException {
    private boolean addInternal(Object key, Registration<TRequest, TListener> registration)
            throws RemoteException {
        Preconditions.checkNotNull(registration);

        synchronized (mListeners) {
            if (mListeners.isEmpty() && !registerService()) {
                return false;
            }
            Registration<T> oldRegistration = mListeners.put(key, registration);
            boolean initialRequest = mListeners.isEmpty();

            Registration<TRequest, TListener> oldRegistration = mListeners.put(key, registration);
            if (oldRegistration != null) {
                oldRegistration.unregister();
            }
            TRequest merged = mergeRequests();

            if (initialRequest || !Objects.equals(merged, mMergedRequest)) {
                mMergedRequest = merged;
                if (!initialRequest) {
                    unregisterService();
                }
                registerService(mMergedRequest);
            }

            return true;
        }
    }

    public void removeListener(Object listener) throws RemoteException {
        synchronized (mListeners) {
            Registration<T> oldRegistration = mListeners.remove(listener);
            Registration<TRequest, TListener> oldRegistration = mListeners.remove(listener);
            if (oldRegistration == null) {
                return;
            }
            oldRegistration.unregister();

            if (mListeners.isEmpty()) {
            boolean lastRequest = mListeners.isEmpty();
            TRequest merged = lastRequest ? null : mergeRequests();
            boolean newRequest = !lastRequest && !Objects.equals(merged, mMergedRequest);

            if (lastRequest || newRequest) {
                unregisterService();
                mMergedRequest = merged;
                if (newRequest) {
                    registerService(mMergedRequest);
                }
            }
        }
    }

    @SuppressWarnings("unchecked")
    protected T convertKey(@NonNull Object listener) {
        return (T) listener;
    protected TListener convertKey(@NonNull Object listener) {
        return (TListener) listener;
    }

    protected abstract boolean registerService() throws RemoteException;
    protected abstract boolean registerService(TRequest request) throws RemoteException;
    protected abstract void unregisterService() throws RemoteException;

    protected void execute(Consumer<T> operation) {
    @Nullable
    protected TRequest merge(@NonNull TRequest[] requests) {
        for (TRequest request : requests) {
            Preconditions.checkArgument(request == null,
                    "merge() has to be overridden for non-null requests.");
        }
        return null;
    }

    protected void execute(Consumer<TListener> operation) {
        synchronized (mListeners) {
            for (Registration<T> registration : mListeners.values()) {
            for (Registration<TRequest, TListener> registration : mListeners.values()) {
                registration.execute(operation);
            }
        }
    }

    @GuardedBy("mListeners")
    @SuppressWarnings("unchecked")
    @Nullable
    private TRequest mergeRequests() {
        Preconditions.checkState(Thread.holdsLock(mListeners));

        if (mListeners.isEmpty()) {
            return null;
        }

        if (mListeners.size() == 1) {
            return mListeners.valueAt(0).getRequest();
        }

        TRequest[] requests = (TRequest[]) new Object[mListeners.size()];
        for (int index = 0; index < mListeners.size(); index++) {
            requests[index] = mListeners.valueAt(index).getRequest();
        }
        return merge(requests);
    }
}
+5 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.GnssMeasurementCorrections;
import android.location.GnssRequest;
import android.location.IBatchedLocationCallback;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssStatusListener;
@@ -69,8 +70,10 @@ interface ILocationManager
        double upperRightLatitude, double upperRightLongitude, int maxResults,
        in GeocoderParams params, out List<Address> addrs);

    boolean addGnssMeasurementsListener(in IGnssMeasurementsListener listener,
             String packageName, String featureId, String listenerIdentifier);
    boolean addGnssMeasurementsListener(in GnssRequest request,
            in IGnssMeasurementsListener listener,
            String packageName, String featureId,
            String listenerIdentifier);
    void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections,
            in String packageName);
    long getGnssCapabilities(in String packageName);
+31 −15
Original line number Diff line number Diff line
@@ -2199,7 +2199,7 @@ public class LocationManager {
     * Registers a GNSS Measurement callback.
     *
     * @param request  extra parameters to pass to GNSS measurement provider. For example, if {@link
     *                 GnssRequest#isFullTrackingEnabled()} is true, GNSS chipset switches off duty
     *                 GnssRequest#isFullTracking()} is true, GNSS chipset switches off duty
     *                 cycling.
     * @param executor the executor that the callback runs on.
     * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
@@ -2216,7 +2216,12 @@ public class LocationManager {
            @NonNull GnssRequest request,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull GnssMeasurementsEvent.Callback callback) {
        throw new RuntimeException();
        Preconditions.checkArgument(request != null, "invalid null request");
        try {
            return mGnssMeasurementsListenerManager.addListener(request, callback, executor);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
@@ -2763,8 +2768,7 @@ public class LocationManager {
    }

    private class GnssStatusListenerManager extends
            AbstractListenerManager<GnssStatus.Callback> {

            AbstractListenerManager<Void, GnssStatus.Callback> {
        @Nullable
        private IGnssStatusListener mListenerTransport;

@@ -2782,19 +2786,19 @@ public class LocationManager {

        public boolean addListener(@NonNull GpsStatus.Listener listener, @NonNull Executor executor)
                throws RemoteException {
            return addInternal(listener, executor);
            return addInternal(null, listener, executor);
        }

        public boolean addListener(@NonNull OnNmeaMessageListener listener,
                @NonNull Handler handler)
                throws RemoteException {
            return addInternal(listener, handler);
            return addInternal(null, listener, handler);
        }

        public boolean addListener(@NonNull OnNmeaMessageListener listener,
                @NonNull Executor executor)
                throws RemoteException {
            return addInternal(listener, executor);
            return addInternal(null, listener, executor);
        }

        @Override
@@ -2833,7 +2837,7 @@ public class LocationManager {
        }

        @Override
        protected boolean registerService() throws RemoteException {
        protected boolean registerService(Void ignored) throws RemoteException {
            Preconditions.checkState(mListenerTransport == null);

            GnssStatusListener transport = new GnssStatusListener();
@@ -2893,17 +2897,17 @@ public class LocationManager {
    }

    private class GnssMeasurementsListenerManager extends
            AbstractListenerManager<GnssMeasurementsEvent.Callback> {
            AbstractListenerManager<GnssRequest, GnssMeasurementsEvent.Callback> {

        @Nullable
        private IGnssMeasurementsListener mListenerTransport;

        @Override
        protected boolean registerService() throws RemoteException {
        protected boolean registerService(GnssRequest request) throws RemoteException {
            Preconditions.checkState(mListenerTransport == null);

            GnssMeasurementsListener transport = new GnssMeasurementsListener();
            if (mService.addGnssMeasurementsListener(transport, mContext.getPackageName(),
            if (mService.addGnssMeasurementsListener(request, transport, mContext.getPackageName(),
                    mContext.getFeatureId(), "gnss measurement callback")) {
                mListenerTransport = transport;
                return true;
@@ -2920,6 +2924,18 @@ public class LocationManager {
            mListenerTransport = null;
        }

        @Override
        @Nullable
        protected GnssRequest merge(@NonNull GnssRequest[] requests) {
            Preconditions.checkArgument(requests.length > 0);
            for (GnssRequest request : requests) {
                if (request.isFullTracking()) {
                    return request;
                }
            }
            return requests[0];
        }

        private class GnssMeasurementsListener extends IGnssMeasurementsListener.Stub {
            @Override
            public void onGnssMeasurementsReceived(final GnssMeasurementsEvent event) {
@@ -2934,13 +2950,13 @@ public class LocationManager {
    }

    private class GnssNavigationMessageListenerManager extends
            AbstractListenerManager<GnssNavigationMessage.Callback> {
            AbstractListenerManager<Void, GnssNavigationMessage.Callback> {

        @Nullable
        private IGnssNavigationMessageListener mListenerTransport;

        @Override
        protected boolean registerService() throws RemoteException {
        protected boolean registerService(Void ignored) throws RemoteException {
            Preconditions.checkState(mListenerTransport == null);

            GnssNavigationMessageListener transport = new GnssNavigationMessageListener();
@@ -2975,13 +2991,13 @@ public class LocationManager {
    }

    private class BatchedLocationCallbackManager extends
            AbstractListenerManager<BatchedLocationCallback> {
            AbstractListenerManager<Void, BatchedLocationCallback> {

        @Nullable
        private IBatchedLocationCallback mListenerTransport;

        @Override
        protected boolean registerService() throws RemoteException {
        protected boolean registerService(Void ignored) throws RemoteException {
            Preconditions.checkState(mListenerTransport == null);

            BatchedLocationCallback transport = new BatchedLocationCallback();
+6 −3
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.GnssMeasurementCorrections;
import android.location.GnssRequest;
import android.location.IBatchedLocationCallback;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
@@ -2287,12 +2288,14 @@ public class LocationManagerService extends ILocationManager.Stub {
    }

    @Override
    public boolean addGnssMeasurementsListener(IGnssMeasurementsListener listener,
            String packageName, String featureId, String listenerIdentifier) {
    public boolean addGnssMeasurementsListener(@Nullable GnssRequest request,
            IGnssMeasurementsListener listener,
            String packageName, String featureId,
            String listenerIdentifier) {
        Objects.requireNonNull(listenerIdentifier);

        return mGnssManagerService != null && mGnssManagerService.addGnssMeasurementsListener(
                listener, packageName, featureId, listenerIdentifier);
                request, listener, packageName, featureId, listenerIdentifier);
    }

    @Override
+11 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -37,22 +38,31 @@ public class LocationManagerServiceUtils {
    /**
     * Listener that can be linked to a binder.
     * @param <TListener> listener type
     * @param <TRequest> request type
     */
    public static class LinkedListener<TListener> extends
    public static class LinkedListener<TRequest, TListener> extends
            LinkedListenerBase {
        @Nullable protected final TRequest mRequest;
        private final TListener mListener;
        private final Consumer<TListener> mBinderDeathCallback;

        public LinkedListener(
                @Nullable TRequest request,
                @NonNull TListener listener,
                String listenerName,
                @NonNull CallerIdentity callerIdentity,
                @NonNull Consumer<TListener> binderDeathCallback) {
            super(callerIdentity, listenerName);
            mListener = listener;
            mRequest = request;
            mBinderDeathCallback = binderDeathCallback;
        }

        @Nullable
        public TRequest getRequest() {
            return mRequest;
        }

        @Override
        public void binderDied() {
            if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
Loading