summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--location/java/android/location/AbstractListenerManager.java129
-rw-r--r--location/java/android/location/ILocationManager.aidl7
-rw-r--r--location/java/android/location/LocationManager.java46
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java9
-rw-r--r--services/core/java/com/android/server/LocationManagerServiceUtils.java12
-rw-r--r--services/core/java/com/android/server/location/GnssMeasurementsProvider.java46
-rw-r--r--services/core/java/com/android/server/location/GnssNavigationMessageProvider.java2
-rw-r--r--services/core/java/com/android/server/location/GnssStatusListenerHelper.java3
-rw-r--r--services/core/java/com/android/server/location/RemoteListenerHelper.java23
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssManagerService.java56
-rw-r--r--services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java22
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();