Add fullTracking to registerGnssMeasurementsCallback (implementation)

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

Bug: 147387008

Test: atest GnssMeasurementsProviderTest
      atest GnssManagerServiceTest
      atest GnssMeasurementRegistrationTest

Change-Id: Iedf03edd7053aa0089cfea0d5c0357322f68d9c4
This commit is contained in:
Yu-Han Yang
2020-01-14 10:51:41 -08:00
parent 729082ca25
commit 519694b50a
11 changed files with 256 additions and 99 deletions

View File

@@ -27,6 +27,7 @@ import android.util.ArrayMap;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -35,26 +36,34 @@ import java.util.function.Consumer;
*
* @hide
*/
abstract class AbstractListenerManager<T> {
abstract class AbstractListenerManager<TRequest, TListener> {
private static class Registration<T> {
private static class Registration<TRequest, TListener> {
private final Executor mExecutor;
@Nullable private volatile T mListener;
@Nullable private TRequest mRequest;
@Nullable private volatile TListener mListener;
private Registration(Executor executor, T listener) {
private Registration(@Nullable TRequest request, Executor executor, TListener listener) {
Preconditions.checkArgument(listener != null, "invalid null listener/callback");
Preconditions.checkArgument(executor != null, "invalid null executor");
mExecutor = executor;
mListener = listener;
mRequest = request;
}
@Nullable
public TRequest getRequest() {
return mRequest;
}
private void unregister() {
mRequest = null;
mListener = null;
}
private void execute(Consumer<T> operation) {
private void execute(Consumer<TListener> operation) {
mExecutor.execute(() -> {
T listener = mListener;
TListener listener = mListener;
if (listener == null) {
return;
}
@@ -71,71 +80,135 @@ abstract class AbstractListenerManager<T> {
}
@GuardedBy("mListeners")
private final ArrayMap<Object, Registration<T>> mListeners = new ArrayMap<>();
private final ArrayMap<Object, Registration<TRequest, TListener>> mListeners =
new ArrayMap<>();
public boolean addListener(@NonNull T listener, @NonNull Handler handler)
@GuardedBy("mListeners")
@Nullable
private TRequest mMergedRequest;
public boolean addListener(@NonNull TListener listener, @NonNull Handler handler)
throws RemoteException {
return addInternal(listener, handler);
return addInternal(/* request= */ null, listener, handler);
}
public boolean addListener(@NonNull T listener, @NonNull Executor executor)
public boolean addListener(@NonNull TListener listener, @NonNull Executor executor)
throws RemoteException {
return addInternal(listener, executor);
return addInternal(/* request= */ null, listener, executor);
}
protected final boolean addInternal(@NonNull Object listener, @NonNull Handler handler)
throws RemoteException {
return addInternal(listener, new HandlerExecutor(handler));
public boolean addListener(@Nullable TRequest request, @NonNull TListener listener,
@NonNull Handler handler) throws RemoteException {
return addInternal(request, listener, handler);
}
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<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);
}
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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

View File

@@ -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.");

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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();