diff options
11 files changed, 256 insertions, 99 deletions
diff --git a/location/java/android/location/AbstractListenerManager.java b/location/java/android/location/AbstractListenerManager.java index 944ebf937dc8..f075a53829ce 100644 --- a/location/java/android/location/AbstractListenerManager.java +++ b/location/java/android/location/AbstractListenerManager.java @@ -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<>(); + + @GuardedBy("mListeners") + @Nullable + private TRequest mMergedRequest; - public boolean addListener(@NonNull T listener, @NonNull Handler handler) + 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); + } } diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 6a5c0ec9457a..030f80a54db9 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -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); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 7e6486cc933e..8afdb7d370d9 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -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(); diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 63cddac0bfba..0b3e3b4d5858 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -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 diff --git a/services/core/java/com/android/server/LocationManagerServiceUtils.java b/services/core/java/com/android/server/LocationManagerServiceUtils.java index 372e91e41772..ba1c81cdd975 100644 --- a/services/core/java/com/android/server/LocationManagerServiceUtils.java +++ b/services/core/java/com/android/server/LocationManagerServiceUtils.java @@ -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."); diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java index 55e427f70180..6ba5f079264c 100644 --- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java @@ -18,6 +18,7 @@ package com.android.server.location; import android.content.Context; import android.location.GnssMeasurementsEvent; +import android.location.GnssRequest; import android.location.IGnssMeasurementsListener; import android.os.Handler; import android.os.RemoteException; @@ -33,14 +34,14 @@ import com.android.internal.annotations.VisibleForTesting; * @hide */ public abstract class GnssMeasurementsProvider - extends RemoteListenerHelper<IGnssMeasurementsListener> { - private static final String TAG = "GnssMeasurementsProvider"; + extends RemoteListenerHelper<GnssRequest, IGnssMeasurementsListener> { + private static final String TAG = "GnssMeasProvider"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final GnssMeasurementProviderNative mNative; - private boolean mIsCollectionStarted; - private boolean mEnableFullTracking; + private boolean mStartedCollection; + private boolean mStartedFullTracking; protected GnssMeasurementsProvider(Context context, Handler handler) { this(context, handler, new GnssMeasurementProviderNative()); @@ -57,8 +58,8 @@ public abstract class GnssMeasurementsProvider if (DEBUG) { Log.d(TAG, "resumeIfStarted"); } - if (mIsCollectionStarted) { - mNative.startMeasurementCollection(mEnableFullTracking); + if (mStartedCollection) { + mNative.startMeasurementCollection(mStartedFullTracking); } } @@ -67,18 +68,35 @@ public abstract class GnssMeasurementsProvider return mNative.isMeasurementSupported(); } - @Override - protected int registerWithService() { + private boolean getMergedFullTracking() { int devOptions = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0); - int fullTrackingToggled = Settings.Global.getInt(mContext.getContentResolver(), + int enableFullTracking = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, 0); - boolean enableFullTracking = (devOptions == 1 /* Developer Mode enabled */) - && (fullTrackingToggled == 1 /* Raw Measurements Full Tracking enabled */); + boolean enableFullTrackingBySetting = (devOptions == 1 /* Developer Mode enabled */) + && (enableFullTracking == 1 /* Raw Measurements Full Tracking enabled */); + if (enableFullTrackingBySetting) { + return true; + } + + synchronized (mListenerMap) { + for (IdentifiedListener identifiedListener : mListenerMap.values()) { + GnssRequest request = identifiedListener.getRequest(); + if (request != null && request.isFullTracking()) { + return true; + } + } + } + return false; + } + + @Override + protected int registerWithService() { + boolean enableFullTracking = getMergedFullTracking(); boolean result = mNative.startMeasurementCollection(enableFullTracking); if (result) { - mIsCollectionStarted = true; - mEnableFullTracking = enableFullTracking; + mStartedCollection = true; + mStartedFullTracking = enableFullTracking; return RemoteListenerHelper.RESULT_SUCCESS; } else { return RemoteListenerHelper.RESULT_INTERNAL_ERROR; @@ -89,7 +107,7 @@ public abstract class GnssMeasurementsProvider protected void unregisterFromService() { boolean stopped = mNative.stopMeasurementCollection(); if (stopped) { - mIsCollectionStarted = false; + mStartedCollection = false; } } diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java index 983d1daa2367..fb901e86f494 100644 --- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java +++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java @@ -33,7 +33,7 @@ import com.android.internal.annotations.VisibleForTesting; * @hide */ public abstract class GnssNavigationMessageProvider - extends RemoteListenerHelper<IGnssNavigationMessageListener> { + extends RemoteListenerHelper<Void, IGnssNavigationMessageListener> { private static final String TAG = "GnssNavigationMessageProvider"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java index eaf63c87d93f..1d16c03fd6f7 100644 --- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java +++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java @@ -24,7 +24,8 @@ import android.util.Log; /** * Implementation of a handler for {@link IGnssStatusListener}. */ -public abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatusListener> { +public abstract class GnssStatusListenerHelper extends + RemoteListenerHelper<Void, IGnssStatusListener> { private static final String TAG = "GnssStatusListenerHelper"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java index 015227394ffe..11f068533a6d 100644 --- a/services/core/java/com/android/server/location/RemoteListenerHelper.java +++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java @@ -17,6 +17,7 @@ package com.android.server.location; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.os.Handler; @@ -32,9 +33,10 @@ import java.util.Objects; /** * A helper class that handles operations in remote listeners. * + * @param <TRequest> the type of request. * @param <TListener> the type of GNSS data listener. */ -public abstract class RemoteListenerHelper<TListener extends IInterface> { +public abstract class RemoteListenerHelper<TRequest, TListener extends IInterface> { protected static final int RESULT_SUCCESS = 0; protected static final int RESULT_NOT_AVAILABLE = 1; @@ -47,7 +49,7 @@ public abstract class RemoteListenerHelper<TListener extends IInterface> { protected final Handler mHandler; private final String mTag; - private final Map<IBinder, IdentifiedListener> mListenerMap = new HashMap<>(); + protected final Map<IBinder, IdentifiedListener> mListenerMap = new HashMap<>(); protected final Context mContext; protected final AppOpsManager mAppOps; @@ -75,7 +77,8 @@ public abstract class RemoteListenerHelper<TListener extends IInterface> { /** * Adds GNSS data listener {@code listener} with caller identify {@code callerIdentify}. */ - public void addListener(@NonNull TListener listener, CallerIdentity callerIdentity) { + public void addListener(@Nullable TRequest request, @NonNull TListener listener, + CallerIdentity callerIdentity) { Objects.requireNonNull(listener, "Attempted to register a 'null' listener."); IBinder binder = listener.asBinder(); synchronized (mListenerMap) { @@ -84,7 +87,7 @@ public abstract class RemoteListenerHelper<TListener extends IInterface> { return; } - IdentifiedListener identifiedListener = new IdentifiedListener(listener, + IdentifiedListener identifiedListener = new IdentifiedListener(request, listener, callerIdentity); mListenerMap.put(binder, identifiedListener); @@ -257,14 +260,22 @@ public abstract class RemoteListenerHelper<TListener extends IInterface> { return RESULT_SUCCESS; } - private class IdentifiedListener { + protected class IdentifiedListener { + @Nullable private final TRequest mRequest; private final TListener mListener; private final CallerIdentity mCallerIdentity; - private IdentifiedListener(@NonNull TListener listener, CallerIdentity callerIdentity) { + private IdentifiedListener(@Nullable TRequest request, @NonNull TListener listener, + CallerIdentity callerIdentity) { mListener = listener; + mRequest = request; mCallerIdentity = callerIdentity; } + + @Nullable + protected TRequest getRequest() { + return mRequest; + } } private class HandlerRunnable implements Runnable { diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index 2bab9fa67eb0..02c1bddd8c00 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -25,6 +25,7 @@ import android.app.AppOpsManager; import android.content.Context; import android.location.GnssCapabilities; import android.location.GnssMeasurementCorrections; +import android.location.GnssRequest; import android.location.IBatchedLocationCallback; import android.location.IGnssMeasurementsListener; import android.location.IGnssNavigationMessageListener; @@ -96,15 +97,15 @@ public class GnssManagerService { private final IGpsGeofenceHardware mGpsGeofenceProxy; @GuardedBy("mGnssMeasurementsListeners") - private final ArrayMap<IBinder, LinkedListener<IGnssMeasurementsListener>> + private final ArrayMap<IBinder, LinkedListener<GnssRequest, IGnssMeasurementsListener>> mGnssMeasurementsListeners = new ArrayMap<>(); @GuardedBy("mGnssNavigationMessageListeners") - private final ArrayMap<IBinder, LinkedListener<IGnssNavigationMessageListener>> + private final ArrayMap<IBinder, LinkedListener<Void, IGnssNavigationMessageListener>> mGnssNavigationMessageListeners = new ArrayMap<>(); @GuardedBy("mGnssStatusListeners") - private final ArrayMap<IBinder, LinkedListener<IGnssStatusListener>> + private final ArrayMap<IBinder, LinkedListener<Void, IGnssStatusListener>> mGnssStatusListeners = new ArrayMap<>(); @GuardedBy("this") @@ -118,7 +119,8 @@ public class GnssManagerService { @Nullable private IBatchedLocationCallback mGnssBatchingCallback; @GuardedBy("mGnssBatchingLock") - @Nullable private LinkedListener<IBatchedLocationCallback> mGnssBatchingDeathCallback; + @Nullable + private LinkedListener<Void, IBatchedLocationCallback> mGnssBatchingDeathCallback; @GuardedBy("mGnssBatchingLock") private boolean mGnssBatchingInProgress = false; @@ -272,6 +274,7 @@ public class GnssManagerService { mGnssBatchingCallback = callback; mGnssBatchingDeathCallback = new LinkedListener<>( + /* request= */ null, callback, "BatchedLocationCallback", callerIdentity, @@ -356,36 +359,39 @@ public class GnssManagerService { } } - private <TListener extends IInterface> void updateListenersOnForegroundChangedLocked( - Map<IBinder, ? extends LinkedListenerBase> gnssDataListeners, - RemoteListenerHelper<TListener> gnssDataProvider, + private <TRequest, TListener extends IInterface> void updateListenersOnForegroundChangedLocked( + Map<IBinder, LinkedListener<TRequest, TListener>> gnssDataListeners, + RemoteListenerHelper<TRequest, TListener> gnssDataProvider, Function<IBinder, TListener> mapBinderToListener, int uid, boolean foreground) { - for (Map.Entry<IBinder, ? extends LinkedListenerBase> entry : + for (Map.Entry<IBinder, LinkedListener<TRequest, TListener>> entry : gnssDataListeners.entrySet()) { - LinkedListenerBase linkedListener = entry.getValue(); + LinkedListener<TRequest, TListener> linkedListener = entry.getValue(); CallerIdentity callerIdentity = linkedListener.getCallerIdentity(); + TRequest request = linkedListener.getRequest(); if (callerIdentity.mUid != uid) { continue; } TListener listener = mapBinderToListener.apply(entry.getKey()); if (foreground || isThrottlingExempt(callerIdentity)) { - gnssDataProvider.addListener(listener, callerIdentity); + gnssDataProvider.addListener(request, listener, callerIdentity); } else { gnssDataProvider.removeListener(listener); } } } - private <TListener extends IInterface> boolean addGnssDataListenerLocked( + private <TListener extends IInterface, TRequest> boolean addGnssDataListenerLocked( + @Nullable TRequest request, TListener listener, String packageName, @Nullable String featureId, @NonNull String listenerIdentifier, - RemoteListenerHelper<TListener> gnssDataProvider, - ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners, + RemoteListenerHelper<TRequest, TListener> gnssDataProvider, + ArrayMap<IBinder, + LinkedListener<TRequest, TListener>> gnssDataListeners, Consumer<TListener> binderDeathCallback) { mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); @@ -395,7 +401,7 @@ public class GnssManagerService { CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), packageName, featureId, listenerIdentifier); - LinkedListener<TListener> linkedListener = new LinkedListener<>(listener, + LinkedListener<TRequest, TListener> linkedListener = new LinkedListener<>(request, listener, listenerIdentifier, callerIdentity, binderDeathCallback); IBinder binder = listener.asBinder(); if (!linkedListener.linkToListenerDeathNotificationLocked(binder)) { @@ -419,15 +425,15 @@ public class GnssManagerService { } if (mAppForegroundHelper.isAppForeground(callerIdentity.mUid) || isThrottlingExempt(callerIdentity)) { - gnssDataProvider.addListener(listener, callerIdentity); + gnssDataProvider.addListener(request, listener, callerIdentity); } return true; } - private <TListener extends IInterface> void removeGnssDataListenerLocked( + private <TRequest, TListener extends IInterface> void removeGnssDataListenerLocked( TListener listener, - RemoteListenerHelper<TListener> gnssDataProvider, - ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners) { + RemoteListenerHelper<TRequest, TListener> gnssDataProvider, + ArrayMap<IBinder, LinkedListener<TRequest, TListener>> gnssDataListeners) { if (gnssDataProvider == null) { Log.e( TAG, @@ -437,7 +443,7 @@ public class GnssManagerService { } IBinder binder = listener.asBinder(); - LinkedListener<TListener> linkedListener = + LinkedListener<TRequest, TListener> linkedListener = gnssDataListeners.remove(binder); if (linkedListener == null) { return; @@ -467,6 +473,7 @@ public class GnssManagerService { @Nullable String featureId) { synchronized (mGnssStatusListeners) { return addGnssDataListenerLocked( + /* request= */ null, listener, packageName, featureId, @@ -489,11 +496,17 @@ public class GnssManagerService { /** * Adds a GNSS measurements listener. */ - public boolean addGnssMeasurementsListener( - IGnssMeasurementsListener listener, String packageName, @Nullable String featureId, + public boolean addGnssMeasurementsListener(@Nullable GnssRequest request, + IGnssMeasurementsListener listener, String packageName, + @Nullable String featureId, @NonNull String listenerIdentifier) { + if (request != null && request.isFullTracking()) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.LOCATION_HARDWARE, + null); + } synchronized (mGnssMeasurementsListeners) { return addGnssDataListenerLocked( + request, listener, packageName, featureId, @@ -538,6 +551,7 @@ public class GnssManagerService { @Nullable String featureId, @NonNull String listenerIdentifier) { synchronized (mGnssNavigationMessageListeners) { return addGnssDataListenerLocked( + /* request= */ null, listener, packageName, featureId, diff --git a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java index f16cf35bfb34..4ba584e67929 100644 --- a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java @@ -39,6 +39,7 @@ import android.location.GnssClock; import android.location.GnssMeasurementCorrections; import android.location.GnssMeasurementsEvent; import android.location.GnssNavigationMessage; +import android.location.GnssRequest; import android.location.GnssSingleSatCorrection; import android.location.IBatchedLocationCallback; import android.location.IGnssMeasurementsListener; @@ -563,7 +564,7 @@ public class GnssManagerServiceTest { assertThrows(SecurityException.class, () -> mGnssManagerService.addGnssMeasurementsListener( - mockGnssMeasurementsListener, + new GnssRequest.Builder().build(), mockGnssMeasurementsListener, "com.android.server", "abcd123", "TestGnssMeasurementsListener")); mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent); @@ -580,8 +581,11 @@ public class GnssManagerServiceTest { enableLocationPermissions(); - assertThat(mGnssManagerService.addGnssMeasurementsListener(mockGnssMeasurementsListener, - "com.android.server", "abcd123", "TestGnssMeasurementsListener")).isEqualTo(true); + assertThat(mGnssManagerService.addGnssMeasurementsListener( + new GnssRequest.Builder().build(), + mockGnssMeasurementsListener, + "com.android.server", "abcd123", + "TestGnssMeasurementsListener")).isEqualTo(true); mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent); verify(mockGnssMeasurementsListener, times(1)).onGnssMeasurementsReceived( @@ -626,8 +630,10 @@ public class GnssManagerServiceTest { enableLocationPermissions(); - mGnssManagerService.addGnssMeasurementsListener(mockGnssMeasurementsListener, - "com.android.server", "abcd123", "TestGnssMeasurementsListener"); + mGnssManagerService.addGnssMeasurementsListener(new GnssRequest.Builder().build(), + mockGnssMeasurementsListener, + "com.android.server", "abcd123", + "TestGnssMeasurementsListener"); disableLocationPermissions(); @@ -648,8 +654,10 @@ public class GnssManagerServiceTest { enableLocationPermissions(); - mGnssManagerService.addGnssMeasurementsListener(mockGnssMeasurementsListener, - "com.android.server", "abcd123", "TestGnssMeasurementsListener"); + mGnssManagerService.addGnssMeasurementsListener(new GnssRequest.Builder().build(), + mockGnssMeasurementsListener, + "com.android.server", "abcd123", + "TestGnssMeasurementsListener"); disableLocationPermissions(); |