• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.location.gnss;
18 
19 import static android.location.LocationManager.GPS_PROVIDER;
20 
21 import android.Manifest;
22 import android.annotation.Nullable;
23 import android.content.Context;
24 import android.location.GnssMeasurementCorrections;
25 import android.location.GnssRequest;
26 import android.location.IBatchedLocationCallback;
27 import android.location.IGnssAntennaInfoListener;
28 import android.location.IGnssMeasurementsListener;
29 import android.location.IGnssNavigationMessageListener;
30 import android.location.IGnssStatusListener;
31 import android.location.IGpsGeofenceHardware;
32 import android.location.INetInitiatedListener;
33 import android.location.Location;
34 import android.location.LocationManagerInternal;
35 import android.os.Binder;
36 import android.os.IBinder;
37 import android.os.IInterface;
38 import android.os.Process;
39 import android.os.RemoteException;
40 import android.stats.location.LocationStatsEnums;
41 import android.util.ArrayMap;
42 import android.util.Log;
43 
44 import com.android.internal.annotations.GuardedBy;
45 import com.android.internal.annotations.VisibleForTesting;
46 import com.android.internal.util.IndentingPrintWriter;
47 import com.android.internal.util.Preconditions;
48 import com.android.server.LocalServices;
49 import com.android.server.location.AppForegroundHelper;
50 import com.android.server.location.AppOpsHelper;
51 import com.android.server.location.CallerIdentity;
52 import com.android.server.location.LocationManagerServiceUtils.LinkedListener;
53 import com.android.server.location.LocationManagerServiceUtils.LinkedListenerBase;
54 import com.android.server.location.LocationUsageLogger;
55 import com.android.server.location.RemoteListenerHelper;
56 import com.android.server.location.SettingsHelper;
57 
58 import java.io.FileDescriptor;
59 import java.io.PrintWriter;
60 import java.util.List;
61 import java.util.Map;
62 import java.util.function.Consumer;
63 import java.util.function.Function;
64 
65 /** Manages Gnss providers and related Gnss functions for LocationManagerService. */
66 public class GnssManagerService {
67 
68     private static final String TAG = "GnssManagerService";
69 
isGnssSupported()70     public static boolean isGnssSupported() {
71         return GnssLocationProvider.isSupported();
72     }
73 
74     private final Context mContext;
75     private final AppOpsHelper mAppOpsHelper;
76     private final SettingsHelper mSettingsHelper;
77     private final AppForegroundHelper mAppForegroundHelper;
78     private final LocationUsageLogger mLocationUsageLogger;
79 
80     private final GnssLocationProvider mGnssLocationProvider;
81     private final GnssStatusListenerHelper mGnssStatusProvider;
82     private final GnssMeasurementsProvider mGnssMeasurementsProvider;
83     private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
84     private final GnssAntennaInfoProvider mGnssAntennaInfoProvider;
85     private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
86     private final GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
87     private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
88     private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
89     private final GnssBatchingProvider mGnssBatchingProvider;
90     private final INetInitiatedListener mNetInitiatedListener;
91     private final IGpsGeofenceHardware mGpsGeofenceProxy;
92 
93     @GuardedBy("mGnssMeasurementsListeners")
94     private final ArrayMap<IBinder, LinkedListener<GnssRequest, IGnssMeasurementsListener>>
95             mGnssMeasurementsListeners = new ArrayMap<>();
96 
97     @GuardedBy("mGnssAntennaInfoListeners")
98     private final ArrayMap<IBinder,
99             LinkedListener<Void, IGnssAntennaInfoListener>>
100             mGnssAntennaInfoListeners = new ArrayMap<>();
101 
102     @GuardedBy("mGnssNavigationMessageListeners")
103     private final ArrayMap<IBinder, LinkedListener<Void, IGnssNavigationMessageListener>>
104             mGnssNavigationMessageListeners = new ArrayMap<>();
105 
106     @GuardedBy("mGnssStatusListeners")
107     private final ArrayMap<IBinder, LinkedListener<Void, IGnssStatusListener>>
108             mGnssStatusListeners = new ArrayMap<>();
109 
110     @GuardedBy("this")
111     @Nullable private LocationManagerInternal mLocationManagerInternal;
112 
113     private final Object mGnssBatchingLock = new Object();
114 
115     @GuardedBy("mGnssBatchingLock")
116     @Nullable private IBatchedLocationCallback mGnssBatchingCallback;
117 
118     @GuardedBy("mGnssBatchingLock")
119     @Nullable
120     private LinkedListener<Void, IBatchedLocationCallback> mGnssBatchingDeathCallback;
121 
122     @GuardedBy("mGnssBatchingLock")
123     private boolean mGnssBatchingInProgress = false;
124 
GnssManagerService(Context context, AppOpsHelper appOpsHelper, SettingsHelper settingsHelper, AppForegroundHelper appForegroundHelper, LocationUsageLogger locationUsageLogger)125     public GnssManagerService(Context context, AppOpsHelper appOpsHelper,
126             SettingsHelper settingsHelper, AppForegroundHelper appForegroundHelper,
127             LocationUsageLogger locationUsageLogger) {
128         this(context, appOpsHelper, settingsHelper, appForegroundHelper, locationUsageLogger, null);
129     }
130 
131     // Can use this constructor to inject GnssLocationProvider for testing
132     @VisibleForTesting
GnssManagerService(Context context, AppOpsHelper appOpsHelper, SettingsHelper settingsHelper, AppForegroundHelper appForegroundHelper, LocationUsageLogger locationUsageLogger, GnssLocationProvider gnssLocationProvider)133     GnssManagerService(Context context, AppOpsHelper appOpsHelper, SettingsHelper settingsHelper,
134             AppForegroundHelper appForegroundHelper, LocationUsageLogger locationUsageLogger,
135             GnssLocationProvider gnssLocationProvider) {
136         Preconditions.checkState(isGnssSupported());
137 
138         mContext = context;
139         mAppOpsHelper = appOpsHelper;
140         mSettingsHelper = settingsHelper;
141         mAppForegroundHelper = appForegroundHelper;
142         mLocationUsageLogger = locationUsageLogger;
143 
144         if (gnssLocationProvider == null) {
145             gnssLocationProvider = new GnssLocationProvider(mContext);
146         }
147 
148         mGnssLocationProvider = gnssLocationProvider;
149         mGnssStatusProvider = mGnssLocationProvider.getGnssStatusProvider();
150         mGnssMeasurementsProvider = mGnssLocationProvider.getGnssMeasurementsProvider();
151         mGnssAntennaInfoProvider = mGnssLocationProvider.getGnssAntennaInfoProvider();
152         mGnssMeasurementCorrectionsProvider =
153                 mGnssLocationProvider.getGnssMeasurementCorrectionsProvider();
154         mGnssNavigationMessageProvider = mGnssLocationProvider.getGnssNavigationMessageProvider();
155         mGnssSystemInfoProvider = mGnssLocationProvider.getGnssSystemInfoProvider();
156         mGnssMetricsProvider = mGnssLocationProvider.getGnssMetricsProvider();
157         mGnssCapabilitiesProvider = mGnssLocationProvider.getGnssCapabilitiesProvider();
158         mGnssBatchingProvider = mGnssLocationProvider.getGnssBatchingProvider();
159         mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener();
160         mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy();
161     }
162 
163     /** Called when system is ready. */
onSystemReady()164     public synchronized void onSystemReady() {
165         if (mLocationManagerInternal != null) {
166             return;
167         }
168 
169         mAppOpsHelper.onSystemReady();
170         mSettingsHelper.onSystemReady();
171         mAppForegroundHelper.onSystemReady();
172 
173         mLocationManagerInternal = LocalServices.getService(LocationManagerInternal.class);
174 
175         mAppForegroundHelper.addListener(this::onAppForegroundChanged);
176     }
177 
178     /** Retrieve the GnssLocationProvider. */
getGnssLocationProvider()179     public GnssLocationProvider getGnssLocationProvider() {
180         return mGnssLocationProvider;
181     }
182 
183     /** Retrieve the IGpsGeofenceHardware. */
getGpsGeofenceProxy()184     public IGpsGeofenceHardware getGpsGeofenceProxy() {
185         return mGpsGeofenceProxy;
186     }
187 
188     /**
189      * Get year of GNSS hardware.
190      */
getGnssYearOfHardware()191     public int getGnssYearOfHardware() {
192         return mGnssSystemInfoProvider.getGnssYearOfHardware();
193     }
194 
195     /**
196      * Get model name of GNSS hardware.
197      */
198     @Nullable
getGnssHardwareModelName()199     public String getGnssHardwareModelName() {
200         return mGnssSystemInfoProvider.getGnssHardwareModelName();
201     }
202 
203     /**
204      * Get GNSS hardware capabilities. The capabilities returned are a bitfield as described in
205      * {@link android.location.GnssCapabilities}.
206      */
getGnssCapabilities()207     public long getGnssCapabilities() {
208         return mGnssCapabilitiesProvider.getGnssCapabilities();
209     }
210 
211     /**
212      * Get size of GNSS batch (GNSS location results are batched together for power savings).
213      */
getGnssBatchSize(String packageName)214     public int getGnssBatchSize(String packageName) {
215         mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
216         mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
217 
218         synchronized (mGnssBatchingLock) {
219             return mGnssBatchingProvider.getBatchSize();
220         }
221     }
222 
223     /**
224      * Starts GNSS batch collection. GNSS positions are collected in a batch before being delivered
225      * as a collection.
226      */
startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName, String featureId)227     public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName,
228             String featureId) {
229         mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
230         mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
231 
232         CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId);
233         if (!mAppOpsHelper.checkLocationAccess(identity)) {
234             return false;
235         }
236 
237         synchronized (mGnssBatchingLock) {
238             if (mGnssBatchingInProgress) {
239                 // Current design does not expect multiple starts to be called repeatedly
240                 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
241                 stopGnssBatch();
242             }
243 
244             mGnssBatchingInProgress = true;
245             return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
246         }
247     }
248 
249     /**
250      * Adds a GNSS batching callback for delivering GNSS location batch results.
251      */
addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName, @Nullable String featureId)252     public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
253             @Nullable String featureId) {
254         mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
255         mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
256 
257         CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId);
258 
259         synchronized (mGnssBatchingLock) {
260             mGnssBatchingCallback = callback;
261             mGnssBatchingDeathCallback =
262                     new LinkedListener<>(
263                             /* request= */ null,
264                             callback,
265                             identity,
266                             (IBatchedLocationCallback listener) -> {
267                                 stopGnssBatch();
268                                 removeGnssBatchingCallback();
269                             });
270 
271             return mGnssBatchingDeathCallback.linkToListenerDeathNotificationLocked(
272                     callback.asBinder());
273         }
274     }
275 
276     /**
277      * Force flush GNSS location results from batch.
278      *
279      * @param packageName name of requesting package
280      */
flushGnssBatch(String packageName)281     public void flushGnssBatch(String packageName) {
282         mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
283         mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
284 
285         synchronized (mGnssBatchingLock) {
286             mGnssBatchingProvider.flush();
287         }
288     }
289 
290     /**
291      * Removes GNSS batching callback.
292      */
removeGnssBatchingCallback()293     public void removeGnssBatchingCallback() {
294         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, null);
295 
296         synchronized (mGnssBatchingLock) {
297             mGnssBatchingDeathCallback.unlinkFromListenerDeathNotificationLocked(
298                     mGnssBatchingCallback.asBinder());
299             mGnssBatchingCallback = null;
300             mGnssBatchingDeathCallback = null;
301         }
302     }
303 
304     /**
305      * Stop GNSS batch collection.
306      */
stopGnssBatch()307     public boolean stopGnssBatch() {
308         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, null);
309 
310         synchronized (mGnssBatchingLock) {
311             mGnssBatchingInProgress = false;
312             return mGnssBatchingProvider.stop();
313         }
314     }
315 
onAppForegroundChanged(int uid, boolean foreground)316     private void onAppForegroundChanged(int uid, boolean foreground) {
317         synchronized (mGnssMeasurementsListeners) {
318             updateListenersOnForegroundChangedLocked(
319                     mGnssMeasurementsListeners,
320                     mGnssMeasurementsProvider,
321                     IGnssMeasurementsListener.Stub::asInterface,
322                     uid,
323                     foreground);
324         }
325         synchronized (mGnssNavigationMessageListeners) {
326             updateListenersOnForegroundChangedLocked(
327                     mGnssNavigationMessageListeners,
328                     mGnssNavigationMessageProvider,
329                     IGnssNavigationMessageListener.Stub::asInterface,
330                     uid,
331                     foreground);
332         }
333         synchronized (mGnssStatusListeners) {
334             updateListenersOnForegroundChangedLocked(
335                     mGnssStatusListeners,
336                     mGnssStatusProvider,
337                     IGnssStatusListener.Stub::asInterface,
338                     uid,
339                     foreground);
340         }
341         synchronized (mGnssAntennaInfoListeners) {
342             updateListenersOnForegroundChangedLocked(
343                     mGnssAntennaInfoListeners,
344                     mGnssAntennaInfoProvider,
345                     IGnssAntennaInfoListener.Stub::asInterface,
346                     uid,
347                     foreground);
348         }
349     }
350 
updateListenersOnForegroundChangedLocked( Map<IBinder, LinkedListener<TRequest, TListener>> gnssDataListeners, RemoteListenerHelper<TRequest, TListener> gnssDataProvider, Function<IBinder, TListener> mapBinderToListener, int uid, boolean foreground)351     private <TRequest, TListener extends IInterface> void updateListenersOnForegroundChangedLocked(
352             Map<IBinder, LinkedListener<TRequest, TListener>> gnssDataListeners,
353             RemoteListenerHelper<TRequest, TListener> gnssDataProvider,
354             Function<IBinder, TListener> mapBinderToListener,
355             int uid,
356             boolean foreground) {
357         for (Map.Entry<IBinder, LinkedListener<TRequest, TListener>> entry :
358                 gnssDataListeners.entrySet()) {
359             LinkedListener<TRequest, TListener> linkedListener = entry.getValue();
360             CallerIdentity callerIdentity = linkedListener.getCallerIdentity();
361             TRequest request = linkedListener.getRequest();
362             if (callerIdentity.uid != uid) {
363                 continue;
364             }
365 
366             TListener listener = mapBinderToListener.apply(entry.getKey());
367             if (foreground || isThrottlingExempt(callerIdentity)) {
368                 gnssDataProvider.addListener(request, listener, callerIdentity);
369             } else {
370                 gnssDataProvider.removeListener(listener);
371             }
372         }
373     }
374 
addGnssDataListenerLocked( @ullable TRequest request, TListener listener, String packageName, @Nullable String featureId, RemoteListenerHelper<TRequest, TListener> gnssDataProvider, ArrayMap<IBinder, LinkedListener<TRequest, TListener>> gnssDataListeners, Consumer<TListener> binderDeathCallback)375     private <TListener extends IInterface, TRequest> boolean addGnssDataListenerLocked(
376             @Nullable TRequest request,
377             TListener listener,
378             String packageName,
379             @Nullable String featureId,
380             RemoteListenerHelper<TRequest, TListener> gnssDataProvider,
381             ArrayMap<IBinder,
382                     LinkedListener<TRequest, TListener>> gnssDataListeners,
383             Consumer<TListener> binderDeathCallback) {
384         mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
385 
386         CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId);
387         if (!mAppOpsHelper.checkLocationAccess(identity)) {
388             return false;
389         }
390 
391         LinkedListener<TRequest, TListener> linkedListener = new LinkedListener<>(request, listener,
392                 identity, binderDeathCallback);
393         IBinder binder = listener.asBinder();
394         if (!linkedListener.linkToListenerDeathNotificationLocked(binder)) {
395             return false;
396         }
397 
398         gnssDataListeners.put(binder, linkedListener);
399         if (gnssDataProvider == mGnssMeasurementsProvider
400                 || gnssDataProvider == mGnssStatusProvider) {
401             mLocationUsageLogger.logLocationApiUsage(
402                     LocationStatsEnums.USAGE_STARTED,
403                     gnssDataProvider == mGnssMeasurementsProvider
404                             ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
405                             : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
406                     packageName,
407                     /* LocationRequest= */ null,
408                     /* hasListener= */ true,
409                     /* hasIntent= */ false,
410                     /* geofence= */ null,
411                     mAppForegroundHelper.getImportance(identity.uid));
412         }
413         if (mAppForegroundHelper.isAppForeground(identity.uid)
414                 || isThrottlingExempt(identity)) {
415             gnssDataProvider.addListener(request, listener, identity);
416         }
417         return true;
418     }
419 
removeGnssDataListenerLocked( TListener listener, RemoteListenerHelper<TRequest, TListener> gnssDataProvider, ArrayMap<IBinder, LinkedListener<TRequest, TListener>> gnssDataListeners)420     private <TRequest, TListener extends IInterface> void removeGnssDataListenerLocked(
421             TListener listener,
422             RemoteListenerHelper<TRequest, TListener> gnssDataProvider,
423             ArrayMap<IBinder, LinkedListener<TRequest, TListener>> gnssDataListeners) {
424         if (gnssDataProvider == null) {
425             Log.e(
426                     TAG,
427                     "Can not remove GNSS data listener. GNSS data provider "
428                             + "not available.");
429             return;
430         }
431 
432         IBinder binder = listener.asBinder();
433         LinkedListener<TRequest, TListener> linkedListener =
434                 gnssDataListeners.remove(binder);
435         if (linkedListener == null) {
436             return;
437         }
438         if (gnssDataProvider == mGnssMeasurementsProvider
439                 || gnssDataProvider == mGnssStatusProvider) {
440             mLocationUsageLogger.logLocationApiUsage(
441                     LocationStatsEnums.USAGE_ENDED,
442                     gnssDataProvider == mGnssMeasurementsProvider
443                             ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
444                             : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
445                     linkedListener.getCallerIdentity().packageName,
446                     /* LocationRequest= */ null,
447                     /* hasListener= */ true,
448                     /* hasIntent= */ false,
449                     /* geofence= */ null,
450                     mAppForegroundHelper.getImportance(Binder.getCallingUid()));
451         }
452         linkedListener.unlinkFromListenerDeathNotificationLocked(binder);
453         gnssDataProvider.removeListener(listener);
454     }
455 
456     /**
457      * Registers listener for GNSS status changes.
458      */
registerGnssStatusCallback(IGnssStatusListener listener, String packageName, @Nullable String featureId)459     public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName,
460             @Nullable String featureId) {
461         synchronized (mGnssStatusListeners) {
462             return addGnssDataListenerLocked(
463                     /* request= */ null,
464                     listener,
465                     packageName,
466                     featureId,
467                     mGnssStatusProvider,
468                     mGnssStatusListeners,
469                     this::unregisterGnssStatusCallback);
470         }
471     }
472 
473     /**
474      * Unregisters listener for GNSS status changes.
475      */
unregisterGnssStatusCallback(IGnssStatusListener listener)476     public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
477         synchronized (mGnssStatusListeners) {
478             removeGnssDataListenerLocked(listener, mGnssStatusProvider, mGnssStatusListeners);
479         }
480     }
481 
482     /**
483      * Adds a GNSS measurements listener.
484      */
addGnssMeasurementsListener(@ullable GnssRequest request, IGnssMeasurementsListener listener, String packageName, @Nullable String featureId)485     public boolean addGnssMeasurementsListener(@Nullable GnssRequest request,
486             IGnssMeasurementsListener listener, String packageName,
487             @Nullable String featureId) {
488         if (request != null && request.isFullTracking()) {
489             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.LOCATION_HARDWARE,
490                     null);
491         }
492         synchronized (mGnssMeasurementsListeners) {
493             return addGnssDataListenerLocked(
494                     request,
495                     listener,
496                     packageName,
497                     featureId,
498                     mGnssMeasurementsProvider,
499                     mGnssMeasurementsListeners,
500                     this::removeGnssMeasurementsListener);
501         }
502     }
503 
504     /**
505      * Injects GNSS measurement corrections.
506      */
injectGnssMeasurementCorrections( GnssMeasurementCorrections measurementCorrections, String packageName)507     public void injectGnssMeasurementCorrections(
508             GnssMeasurementCorrections measurementCorrections, String packageName) {
509         mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
510         mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
511 
512         mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(
513                 measurementCorrections);
514     }
515 
516     /**
517      * Removes a GNSS measurements listener.
518      */
removeGnssMeasurementsListener(IGnssMeasurementsListener listener)519     public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
520         synchronized (mGnssMeasurementsListeners) {
521             removeGnssDataListenerLocked(listener, mGnssMeasurementsProvider,
522                     mGnssMeasurementsListeners);
523         }
524     }
525 
526     /**
527      * Adds a GNSS Antenna Info listener.
528      *
529      * @param listener    called when GNSS antenna info is received
530      * @param packageName name of requesting package
531      */
addGnssAntennaInfoListener( IGnssAntennaInfoListener listener, String packageName, @Nullable String featureId)532     public boolean addGnssAntennaInfoListener(
533             IGnssAntennaInfoListener listener, String packageName,
534             @Nullable String featureId) {
535         synchronized (mGnssAntennaInfoListeners) {
536             return addGnssDataListenerLocked(
537                     /* request= */ null,
538                     listener,
539                     packageName,
540                     featureId,
541                     mGnssAntennaInfoProvider,
542                     mGnssAntennaInfoListeners,
543                     this::removeGnssAntennaInfoListener);
544         }
545     }
546 
547     /**
548      * Removes a GNSS Antenna Info listener.
549      *
550      * @param listener called when GNSS antenna info is received
551      */
removeGnssAntennaInfoListener(IGnssAntennaInfoListener listener)552     public void removeGnssAntennaInfoListener(IGnssAntennaInfoListener listener) {
553         synchronized (mGnssAntennaInfoListeners) {
554             removeGnssDataListenerLocked(
555                     listener, mGnssAntennaInfoProvider, mGnssAntennaInfoListeners);
556         }
557     }
558 
559     /**
560      * Adds a GNSS navigation message listener.
561      */
addGnssNavigationMessageListener( IGnssNavigationMessageListener listener, String packageName, @Nullable String featureId)562     public boolean addGnssNavigationMessageListener(
563             IGnssNavigationMessageListener listener, String packageName,
564             @Nullable String featureId) {
565         synchronized (mGnssNavigationMessageListeners) {
566             return addGnssDataListenerLocked(
567                     /* request= */ null,
568                     listener,
569                     packageName,
570                     featureId,
571                     mGnssNavigationMessageProvider,
572                     mGnssNavigationMessageListeners,
573                     this::removeGnssNavigationMessageListener);
574         }
575     }
576 
577     /**
578      * Removes a GNSS navigation message listener.
579      */
removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener)580     public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
581         synchronized (mGnssNavigationMessageListeners) {
582             removeGnssDataListenerLocked(
583                     listener, mGnssNavigationMessageProvider, mGnssNavigationMessageListeners);
584         }
585     }
586 
587     /**
588      * Send Ni Response, indicating a location request initiated by a network carrier.
589      */
sendNiResponse(int notifId, int userResponse)590     public void sendNiResponse(int notifId, int userResponse) {
591         try {
592             mNetInitiatedListener.sendNiResponse(notifId, userResponse);
593         } catch (RemoteException e) {
594             Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
595         }
596     }
597 
598     /**
599      * Report location results to GNSS batching listener.
600      */
onReportLocation(List<Location> locations)601     public void onReportLocation(List<Location> locations) {
602         IBatchedLocationCallback gnssBatchingCallback;
603         LinkedListener<Void, IBatchedLocationCallback> gnssBatchingDeathCallback;
604         synchronized (mGnssBatchingLock) {
605             gnssBatchingCallback = mGnssBatchingCallback;
606             gnssBatchingDeathCallback = mGnssBatchingDeathCallback;
607         }
608 
609         if (gnssBatchingCallback == null || gnssBatchingDeathCallback == null) {
610             return;
611         }
612 
613         int userId = gnssBatchingDeathCallback.getCallerIdentity().userId;
614         if (!mLocationManagerInternal.isProviderEnabledForUser(GPS_PROVIDER, userId)) {
615             Log.w(TAG, "reportLocationBatch() called without user permission");
616             return;
617         }
618 
619         try {
620             gnssBatchingCallback.onLocationBatch(locations);
621         } catch (RemoteException e) {
622             Log.e(TAG, "reportLocationBatch() failed", e);
623         }
624     }
625 
isThrottlingExempt(CallerIdentity callerIdentity)626     private boolean isThrottlingExempt(CallerIdentity callerIdentity) {
627         if (callerIdentity.uid == Process.SYSTEM_UID) {
628             return true;
629         }
630 
631         if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
632                 callerIdentity.packageName)) {
633             return true;
634         }
635 
636         synchronized (this) {
637             Preconditions.checkState(mLocationManagerInternal != null);
638         }
639         return mLocationManagerInternal.isProviderPackage(callerIdentity.packageName);
640     }
641 
642     /**
643      * Dump info for debugging.
644      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)645     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
646         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
647 
648         if (args.length > 0 && args[0].equals("--gnssmetrics")) {
649             if (mGnssMetricsProvider != null) {
650                 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
651             }
652             return;
653         }
654 
655         ipw.println("GnssMeasurement Listeners:");
656         ipw.increaseIndent();
657         synchronized (mGnssMeasurementsListeners) {
658             for (LinkedListenerBase listener : mGnssMeasurementsListeners.values()) {
659                 ipw.println(listener);
660             }
661         }
662         ipw.decreaseIndent();
663 
664         ipw.println("GnssNavigationMessage Listeners:");
665         ipw.increaseIndent();
666         synchronized (mGnssNavigationMessageListeners) {
667             for (LinkedListenerBase listener : mGnssNavigationMessageListeners.values()) {
668                 ipw.println(listener);
669             }
670         }
671         ipw.decreaseIndent();
672 
673         ipw.println("GnssStatus Listeners:");
674         ipw.increaseIndent();
675         synchronized (mGnssStatusListeners) {
676             for (LinkedListenerBase listener : mGnssStatusListeners.values()) {
677                 ipw.println(listener);
678             }
679         }
680         ipw.decreaseIndent();
681 
682         synchronized (mGnssBatchingLock) {
683             if (mGnssBatchingInProgress) {
684                 ipw.println("GNSS batching in progress");
685             }
686         }
687     }
688 }
689