diff --git a/location/java/android/location/AbstractListenerManager.java b/location/java/android/location/AbstractListenerManager.java index 944ebf937dc85..f075a53829ce0 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 { +abstract class AbstractListenerManager { - private static class Registration { + private static class Registration { 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 operation) { + private void execute(Consumer operation) { mExecutor.execute(() -> { - T listener = mListener; + TListener listener = mListener; if (listener == null) { return; } @@ -71,71 +80,135 @@ abstract class AbstractListenerManager { } @GuardedBy("mListeners") - private final ArrayMap> mListeners = new ArrayMap<>(); + private final ArrayMap> 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); } - protected final boolean addInternal(@NonNull Object listener, @NonNull Executor executor) + 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(@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 registration) throws RemoteException { + private boolean addInternal(Object key, Registration registration) + throws RemoteException { Preconditions.checkNotNull(registration); synchronized (mListeners) { - if (mListeners.isEmpty() && !registerService()) { - return false; - } - Registration oldRegistration = mListeners.put(key, registration); + boolean initialRequest = mListeners.isEmpty(); + + Registration 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 oldRegistration = mListeners.remove(listener); + Registration 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 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 operation) { synchronized (mListeners) { - for (Registration registration : mListeners.values()) { + for (Registration 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 6a5c0ec9457a8..030f80a54db95 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
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 7e6486cc933e6..8afdb7d370d96 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 { - + AbstractListenerManager { @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 { + AbstractListenerManager { @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 { + AbstractListenerManager { @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 { + AbstractListenerManager { @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 63cddac0bfba5..0b3e3b4d58585 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 372e91e417720..ba1c81cdd9757 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 listener type + * @param request type */ - public static class LinkedListener extends + public static class LinkedListener extends LinkedListenerBase { + @Nullable protected final TRequest mRequest; private final TListener mListener; private final Consumer mBinderDeathCallback; public LinkedListener( + @Nullable TRequest request, @NonNull TListener listener, String listenerName, @NonNull CallerIdentity callerIdentity, @NonNull Consumer 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 55e427f70180f..6ba5f079264cb 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 { - private static final String TAG = "GnssMeasurementsProvider"; + extends RemoteListenerHelper { + 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 983d1daa23679..fb901e86f494f 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 { + extends RemoteListenerHelper { 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 eaf63c87d93fa..1d16c03fd6f7a 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 { +public abstract class GnssStatusListenerHelper extends + RemoteListenerHelper { 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 015227394ffe6..11f068533a6df 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 the type of request. * @param the type of GNSS data listener. */ -public abstract class RemoteListenerHelper { +public abstract class RemoteListenerHelper { protected static final int RESULT_SUCCESS = 0; protected static final int RESULT_NOT_AVAILABLE = 1; @@ -47,7 +49,7 @@ public abstract class RemoteListenerHelper { protected final Handler mHandler; private final String mTag; - private final Map mListenerMap = new HashMap<>(); + protected final Map mListenerMap = new HashMap<>(); protected final Context mContext; protected final AppOpsManager mAppOps; @@ -75,7 +77,8 @@ public abstract class RemoteListenerHelper { /** * 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 { 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 { 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 2bab9fa67eb00..02c1bddd8c004 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> + private final ArrayMap> mGnssMeasurementsListeners = new ArrayMap<>(); @GuardedBy("mGnssNavigationMessageListeners") - private final ArrayMap> + private final ArrayMap> mGnssNavigationMessageListeners = new ArrayMap<>(); @GuardedBy("mGnssStatusListeners") - private final ArrayMap> + private final ArrayMap> mGnssStatusListeners = new ArrayMap<>(); @GuardedBy("this") @@ -118,7 +119,8 @@ public class GnssManagerService { @Nullable private IBatchedLocationCallback mGnssBatchingCallback; @GuardedBy("mGnssBatchingLock") - @Nullable private LinkedListener mGnssBatchingDeathCallback; + @Nullable + private LinkedListener 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 void updateListenersOnForegroundChangedLocked( - Map gnssDataListeners, - RemoteListenerHelper gnssDataProvider, + private void updateListenersOnForegroundChangedLocked( + Map> gnssDataListeners, + RemoteListenerHelper gnssDataProvider, Function mapBinderToListener, int uid, boolean foreground) { - for (Map.Entry entry : + for (Map.Entry> entry : gnssDataListeners.entrySet()) { - LinkedListenerBase linkedListener = entry.getValue(); + LinkedListener 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 boolean addGnssDataListenerLocked( + private boolean addGnssDataListenerLocked( + @Nullable TRequest request, TListener listener, String packageName, @Nullable String featureId, @NonNull String listenerIdentifier, - RemoteListenerHelper gnssDataProvider, - ArrayMap> gnssDataListeners, + RemoteListenerHelper gnssDataProvider, + ArrayMap> gnssDataListeners, Consumer 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 linkedListener = new LinkedListener<>(listener, + LinkedListener 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 void removeGnssDataListenerLocked( + private void removeGnssDataListenerLocked( TListener listener, - RemoteListenerHelper gnssDataProvider, - ArrayMap> gnssDataListeners) { + RemoteListenerHelper gnssDataProvider, + ArrayMap> gnssDataListeners) { if (gnssDataProvider == null) { Log.e( TAG, @@ -437,7 +443,7 @@ public class GnssManagerService { } IBinder binder = listener.asBinder(); - LinkedListener linkedListener = + LinkedListener 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 f16cf35bfb34c..4ba584e679291 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();