blob: 2bab9fa67eb00c513734acca6a762c281efcdc7c [file] [log] [blame]
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07001/*
Soonil Nagarkarf20d10e2020-01-27 11:05:40 -08002 * Copyright (C) 2020 The Android Open Source Project
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -07003 *
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
Soonil Nagarkarf20d10e2020-01-27 11:05:40 -080017package com.android.server.location.gnss;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070018
Soonil Nagarkarb6375a42020-01-29 15:23:06 -080019import static android.app.AppOpsManager.OP_FINE_LOCATION;
20
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070021import android.Manifest;
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -070022import android.annotation.NonNull;
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -070023import android.annotation.Nullable;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070024import android.app.AppOpsManager;
25import android.content.Context;
26import android.location.GnssCapabilities;
27import android.location.GnssMeasurementCorrections;
28import android.location.IBatchedLocationCallback;
29import android.location.IGnssMeasurementsListener;
30import android.location.IGnssNavigationMessageListener;
31import android.location.IGnssStatusListener;
32import android.location.IGpsGeofenceHardware;
33import android.location.INetInitiatedListener;
34import android.location.Location;
Soonil Nagarkarb6375a42020-01-29 15:23:06 -080035import android.location.LocationManagerInternal;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070036import android.os.Binder;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070037import android.os.IBinder;
38import android.os.IInterface;
39import android.os.Process;
40import android.os.RemoteException;
41import android.stats.location.LocationStatsEnums;
42import android.util.ArrayMap;
43import android.util.Log;
44
45import com.android.internal.annotations.GuardedBy;
46import com.android.internal.annotations.VisibleForTesting;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070047import com.android.internal.util.IndentingPrintWriter;
Soonil Nagarkarb6375a42020-01-29 15:23:06 -080048import com.android.internal.util.Preconditions;
49import com.android.server.LocalServices;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070050import com.android.server.LocationManagerServiceUtils.LinkedListener;
51import com.android.server.LocationManagerServiceUtils.LinkedListenerBase;
Soonil Nagarkarb6375a42020-01-29 15:23:06 -080052import com.android.server.location.AppForegroundHelper;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070053import com.android.server.location.CallerIdentity;
54import com.android.server.location.GnssBatchingProvider;
55import com.android.server.location.GnssCapabilitiesProvider;
56import com.android.server.location.GnssLocationProvider;
57import com.android.server.location.GnssMeasurementCorrectionsProvider;
58import com.android.server.location.GnssMeasurementsProvider;
59import com.android.server.location.GnssNavigationMessageProvider;
60import com.android.server.location.GnssStatusListenerHelper;
Soonil Nagarkar3f128402019-12-12 08:31:27 -080061import com.android.server.location.LocationUsageLogger;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070062import com.android.server.location.RemoteListenerHelper;
Soonil Nagarkarb6375a42020-01-29 15:23:06 -080063import com.android.server.location.SettingsHelper;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070064
65import java.io.FileDescriptor;
66import java.io.PrintWriter;
67import java.util.List;
68import java.util.Map;
69import java.util.function.Consumer;
70import java.util.function.Function;
71
72/** Manages Gnss providers and related Gnss functions for LocationManagerService. */
73public class GnssManagerService {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070074
Soonil Nagarkarb6375a42020-01-29 15:23:06 -080075 private static final String TAG = "GnssManagerService";
76
77 public static boolean isGnssSupported() {
78 return GnssLocationProvider.isSupported();
79 }
80
81 private final Context mContext;
82 private final SettingsHelper mSettingsHelper;
83 private final AppForegroundHelper mAppForegroundHelper;
84 private final LocationUsageLogger mLocationUsageLogger;
85
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070086 private final GnssLocationProvider mGnssLocationProvider;
87 private final GnssStatusListenerHelper mGnssStatusProvider;
88 private final GnssMeasurementsProvider mGnssMeasurementsProvider;
89 private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
90 private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
91 private final GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
92 private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
93 private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
94 private final GnssBatchingProvider mGnssBatchingProvider;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070095 private final INetInitiatedListener mNetInitiatedListener;
96 private final IGpsGeofenceHardware mGpsGeofenceProxy;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -070097
98 @GuardedBy("mGnssMeasurementsListeners")
Soonil Nagarkarb6375a42020-01-29 15:23:06 -080099 private final ArrayMap<IBinder, LinkedListener<IGnssMeasurementsListener>>
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700100 mGnssMeasurementsListeners = new ArrayMap<>();
101
102 @GuardedBy("mGnssNavigationMessageListeners")
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800103 private final ArrayMap<IBinder, LinkedListener<IGnssNavigationMessageListener>>
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700104 mGnssNavigationMessageListeners = new ArrayMap<>();
105
106 @GuardedBy("mGnssStatusListeners")
107 private final ArrayMap<IBinder, LinkedListener<IGnssStatusListener>>
108 mGnssStatusListeners = new ArrayMap<>();
109
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800110 @GuardedBy("this")
111 @Nullable private LocationManagerInternal mLocationManagerInternal;
112 @GuardedBy("this")
113 @Nullable private AppOpsManager mAppOpsManager;
114
115 private final Object mGnssBatchingLock = new Object();
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700116
117 @GuardedBy("mGnssBatchingLock")
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800118 @Nullable private IBatchedLocationCallback mGnssBatchingCallback;
119
120 @GuardedBy("mGnssBatchingLock")
121 @Nullable private LinkedListener<IBatchedLocationCallback> mGnssBatchingDeathCallback;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700122
123 @GuardedBy("mGnssBatchingLock")
124 private boolean mGnssBatchingInProgress = false;
125
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800126 public GnssManagerService(Context context, SettingsHelper settingsHelper,
127 AppForegroundHelper appForegroundHelper, LocationUsageLogger locationUsageLogger) {
128 this(context, settingsHelper, appForegroundHelper, locationUsageLogger, null);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700129 }
130
131 // Can use this constructor to inject GnssLocationProvider for testing
132 @VisibleForTesting
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800133 GnssManagerService(Context context, SettingsHelper settingsHelper,
134 AppForegroundHelper appForegroundHelper, LocationUsageLogger locationUsageLogger,
135 GnssLocationProvider gnssLocationProvider) {
136 Preconditions.checkState(isGnssSupported());
137
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700138 mContext = context;
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800139 mSettingsHelper = settingsHelper;
140 mAppForegroundHelper = appForegroundHelper;
141 mLocationUsageLogger = locationUsageLogger;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700142
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800143 if (gnssLocationProvider == null) {
144 gnssLocationProvider = new GnssLocationProvider(mContext);
145 }
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700146
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800147 mGnssLocationProvider = gnssLocationProvider;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700148 mGnssStatusProvider = mGnssLocationProvider.getGnssStatusProvider();
149 mGnssMeasurementsProvider = mGnssLocationProvider.getGnssMeasurementsProvider();
150 mGnssMeasurementCorrectionsProvider =
151 mGnssLocationProvider.getGnssMeasurementCorrectionsProvider();
152 mGnssNavigationMessageProvider = mGnssLocationProvider.getGnssNavigationMessageProvider();
153 mGnssSystemInfoProvider = mGnssLocationProvider.getGnssSystemInfoProvider();
154 mGnssMetricsProvider = mGnssLocationProvider.getGnssMetricsProvider();
155 mGnssCapabilitiesProvider = mGnssLocationProvider.getGnssCapabilitiesProvider();
156 mGnssBatchingProvider = mGnssLocationProvider.getGnssBatchingProvider();
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700157 mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener();
158 mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy();
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700159 }
160
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800161 /** Called when system is ready. */
162 public synchronized void onSystemReady() {
163 if (mLocationManagerInternal != null) {
164 return;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700165 }
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800166
167 mSettingsHelper.onSystemReady();
168 mAppForegroundHelper.onSystemReady();
169
170 mLocationManagerInternal = LocalServices.getService(LocationManagerInternal.class);
171 mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
172
173 mAppForegroundHelper.addListener(this::onAppForegroundChanged);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700174 }
175
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800176 /** Retrieve the GnssLocationProvider. */
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700177 public GnssLocationProvider getGnssLocationProvider() {
178 return mGnssLocationProvider;
179 }
180
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800181 /** Retrieve the IGpsGeofenceHardware. */
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700182 public IGpsGeofenceHardware getGpsGeofenceProxy() {
183 return mGpsGeofenceProxy;
184 }
185
186 /**
187 * Get year of GNSS hardware.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700188 */
189 public int getGnssYearOfHardware() {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800190 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700191 }
192
193 /**
194 * Get model name of GNSS hardware.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700195 */
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800196 @Nullable
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700197 public String getGnssHardwareModelName() {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800198 return mGnssSystemInfoProvider.getGnssHardwareModelName();
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700199 }
200
201 /**
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800202 * Get GNSS hardware capabilities. The capabilities returned are a bitfield as described in
203 * {@link android.location.GnssCapabilities}.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700204 */
205 public long getGnssCapabilities(String packageName) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800206 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
207 mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
208
209 if (!checkLocationAppOp(packageName)) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700210 return GnssCapabilities.INVALID_CAPABILITIES;
211 }
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800212
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700213 return mGnssCapabilitiesProvider.getGnssCapabilities();
214 }
215
216 /**
217 * Get size of GNSS batch (GNSS location results are batched together for power savings).
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700218 */
219 public int getGnssBatchSize(String packageName) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800220 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
221 mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700222
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800223 if (!checkLocationAppOp(packageName)) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700224 return 0;
225 }
226
227 synchronized (mGnssBatchingLock) {
228 return mGnssBatchingProvider.getBatchSize();
229 }
230 }
231
232 /**
233 * Starts GNSS batch collection. GNSS positions are collected in a batch before being delivered
234 * as a collection.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700235 */
236 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800237 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
238 mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700239
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800240 if (!checkLocationAppOp(packageName)) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700241 return false;
242 }
243
244 synchronized (mGnssBatchingLock) {
245 if (mGnssBatchingInProgress) {
246 // Current design does not expect multiple starts to be called repeatedly
247 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700248 stopGnssBatch();
249 }
250
251 mGnssBatchingInProgress = true;
252 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
253 }
254 }
255
256 /**
257 * Adds a GNSS batching callback for delivering GNSS location batch results.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700258 */
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -0700259 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -0700260 @Nullable String featureId, @NonNull String listenerIdentity) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800261 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
262 mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700263
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800264 if (!checkLocationAppOp(packageName)) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700265 return false;
266 }
267
268 CallerIdentity callerIdentity =
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -0700269 new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -0700270 featureId, listenerIdentity);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700271 synchronized (mGnssBatchingLock) {
272 mGnssBatchingCallback = callback;
273 mGnssBatchingDeathCallback =
Soonil Nagarkarf20d10e2020-01-27 11:05:40 -0800274 new LinkedListener<>(
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700275 callback,
276 "BatchedLocationCallback",
277 callerIdentity,
278 (IBatchedLocationCallback listener) -> {
279 stopGnssBatch();
280 removeGnssBatchingCallback();
281 });
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800282
283 return mGnssBatchingDeathCallback.linkToListenerDeathNotificationLocked(
284 callback.asBinder());
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700285 }
286 }
287
288 /**
289 * Force flush GNSS location results from batch.
290 *
291 * @param packageName name of requesting package
292 */
293 public void flushGnssBatch(String packageName) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800294 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
295 mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700296
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800297 if (!checkLocationAppOp(packageName)) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700298 return;
299 }
300
301 synchronized (mGnssBatchingLock) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700302 mGnssBatchingProvider.flush();
303 }
304 }
305
306 /**
307 * Removes GNSS batching callback.
308 */
309 public void removeGnssBatchingCallback() {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800310 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, null);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700311
312 synchronized (mGnssBatchingLock) {
313 mGnssBatchingDeathCallback.unlinkFromListenerDeathNotificationLocked(
314 mGnssBatchingCallback.asBinder());
315 mGnssBatchingCallback = null;
316 mGnssBatchingDeathCallback = null;
317 }
318 }
319
320 /**
321 * Stop GNSS batch collection.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700322 */
323 public boolean stopGnssBatch() {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800324 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE, null);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700325
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700326 synchronized (mGnssBatchingLock) {
327 mGnssBatchingInProgress = false;
328 return mGnssBatchingProvider.stop();
329 }
330 }
331
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800332 private void onAppForegroundChanged(int uid, boolean foreground) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700333 synchronized (mGnssMeasurementsListeners) {
334 updateListenersOnForegroundChangedLocked(
335 mGnssMeasurementsListeners,
336 mGnssMeasurementsProvider,
337 IGnssMeasurementsListener.Stub::asInterface,
338 uid,
339 foreground);
340 }
341 synchronized (mGnssNavigationMessageListeners) {
342 updateListenersOnForegroundChangedLocked(
343 mGnssNavigationMessageListeners,
344 mGnssNavigationMessageProvider,
345 IGnssNavigationMessageListener.Stub::asInterface,
346 uid,
347 foreground);
348 }
349 synchronized (mGnssStatusListeners) {
350 updateListenersOnForegroundChangedLocked(
351 mGnssStatusListeners,
352 mGnssStatusProvider,
353 IGnssStatusListener.Stub::asInterface,
354 uid,
355 foreground);
356 }
357 }
358
359 private <TListener extends IInterface> void updateListenersOnForegroundChangedLocked(
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800360 Map<IBinder, ? extends LinkedListenerBase> gnssDataListeners,
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700361 RemoteListenerHelper<TListener> gnssDataProvider,
362 Function<IBinder, TListener> mapBinderToListener,
363 int uid,
364 boolean foreground) {
365 for (Map.Entry<IBinder, ? extends LinkedListenerBase> entry :
366 gnssDataListeners.entrySet()) {
367 LinkedListenerBase linkedListener = entry.getValue();
368 CallerIdentity callerIdentity = linkedListener.getCallerIdentity();
369 if (callerIdentity.mUid != uid) {
370 continue;
371 }
372
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700373 TListener listener = mapBinderToListener.apply(entry.getKey());
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800374 if (foreground || isThrottlingExempt(callerIdentity)) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700375 gnssDataProvider.addListener(listener, callerIdentity);
376 } else {
377 gnssDataProvider.removeListener(listener);
378 }
379 }
380 }
381
382 private <TListener extends IInterface> boolean addGnssDataListenerLocked(
383 TListener listener,
384 String packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -0700385 @Nullable String featureId,
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -0700386 @NonNull String listenerIdentifier,
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700387 RemoteListenerHelper<TListener> gnssDataProvider,
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800388 ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners,
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700389 Consumer<TListener> binderDeathCallback) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800390 mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
391
392 if (!checkLocationAppOp(packageName)) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700393 return false;
394 }
395
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800396 CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
397 Binder.getCallingPid(), packageName, featureId, listenerIdentifier);
398 LinkedListener<TListener> linkedListener = new LinkedListener<>(listener,
399 listenerIdentifier, callerIdentity, binderDeathCallback);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700400 IBinder binder = listener.asBinder();
401 if (!linkedListener.linkToListenerDeathNotificationLocked(binder)) {
402 return false;
403 }
404
405 gnssDataListeners.put(binder, linkedListener);
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800406 if (gnssDataProvider == mGnssMeasurementsProvider
407 || gnssDataProvider == mGnssStatusProvider) {
408 mLocationUsageLogger.logLocationApiUsage(
409 LocationStatsEnums.USAGE_STARTED,
410 gnssDataProvider == mGnssMeasurementsProvider
411 ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
412 : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
413 packageName,
414 /* LocationRequest= */ null,
415 /* hasListener= */ true,
416 /* hasIntent= */ false,
417 /* geofence= */ null,
418 mAppForegroundHelper.getImportance(callerIdentity.mUid));
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700419 }
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800420 if (mAppForegroundHelper.isAppForeground(callerIdentity.mUid)
421 || isThrottlingExempt(callerIdentity)) {
422 gnssDataProvider.addListener(listener, callerIdentity);
423 }
424 return true;
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700425 }
426
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800427 private <TListener extends IInterface> void removeGnssDataListenerLocked(
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700428 TListener listener,
429 RemoteListenerHelper<TListener> gnssDataProvider,
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800430 ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700431 if (gnssDataProvider == null) {
432 Log.e(
433 TAG,
434 "Can not remove GNSS data listener. GNSS data provider "
435 + "not available.");
436 return;
437 }
438
439 IBinder binder = listener.asBinder();
440 LinkedListener<TListener> linkedListener =
441 gnssDataListeners.remove(binder);
442 if (linkedListener == null) {
443 return;
444 }
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800445 if (gnssDataProvider == mGnssMeasurementsProvider
446 || gnssDataProvider == mGnssStatusProvider) {
447 mLocationUsageLogger.logLocationApiUsage(
448 LocationStatsEnums.USAGE_ENDED,
449 gnssDataProvider == mGnssMeasurementsProvider
450 ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
451 : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
452 linkedListener.getCallerIdentity().mPackageName,
453 /* LocationRequest= */ null,
454 /* hasListener= */ true,
455 /* hasIntent= */ false,
456 /* geofence= */ null,
457 mAppForegroundHelper.getImportance(Binder.getCallingUid()));
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700458 }
459 linkedListener.unlinkFromListenerDeathNotificationLocked(binder);
460 gnssDataProvider.removeListener(listener);
461 }
462
463 /**
464 * Registers listener for GNSS status changes.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700465 */
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -0700466 public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName,
467 @Nullable String featureId) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700468 synchronized (mGnssStatusListeners) {
469 return addGnssDataListenerLocked(
470 listener,
471 packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -0700472 featureId,
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -0700473 "Gnss status",
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700474 mGnssStatusProvider,
475 mGnssStatusListeners,
476 this::unregisterGnssStatusCallback);
477 }
478 }
479
480 /**
481 * Unregisters listener for GNSS status changes.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700482 */
483 public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
484 synchronized (mGnssStatusListeners) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800485 removeGnssDataListenerLocked(listener, mGnssStatusProvider, mGnssStatusListeners);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700486 }
487 }
488
489 /**
490 * Adds a GNSS measurements listener.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700491 */
492 public boolean addGnssMeasurementsListener(
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -0700493 IGnssMeasurementsListener listener, String packageName, @Nullable String featureId,
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -0700494 @NonNull String listenerIdentifier) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700495 synchronized (mGnssMeasurementsListeners) {
496 return addGnssDataListenerLocked(
497 listener,
498 packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -0700499 featureId,
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -0700500 listenerIdentifier,
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700501 mGnssMeasurementsProvider,
502 mGnssMeasurementsListeners,
503 this::removeGnssMeasurementsListener);
504 }
505 }
506
507 /**
508 * Injects GNSS measurement corrections.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700509 */
510 public void injectGnssMeasurementCorrections(
511 GnssMeasurementCorrections measurementCorrections, String packageName) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800512 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE, null);
513 mContext.enforceCallingPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
514
515 if (!checkLocationAppOp(packageName)) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700516 return;
517 }
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800518
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700519 mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(
520 measurementCorrections);
521 }
522
523 /**
524 * Removes a GNSS measurements listener.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700525 */
526 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
527 synchronized (mGnssMeasurementsListeners) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800528 removeGnssDataListenerLocked(listener, mGnssMeasurementsProvider,
529 mGnssMeasurementsListeners);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700530 }
531 }
532
533 /**
534 * Adds a GNSS navigation message listener.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700535 */
536 public boolean addGnssNavigationMessageListener(
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -0700537 IGnssNavigationMessageListener listener, String packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -0700538 @Nullable String featureId, @NonNull String listenerIdentifier) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700539 synchronized (mGnssNavigationMessageListeners) {
540 return addGnssDataListenerLocked(
541 listener,
542 packageName,
Philip P. Moltmann6c7377c2019-09-27 17:06:25 -0700543 featureId,
Philip P. Moltmannbc8b48a2019-09-27 17:06:25 -0700544 listenerIdentifier,
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700545 mGnssNavigationMessageProvider,
546 mGnssNavigationMessageListeners,
547 this::removeGnssNavigationMessageListener);
548 }
549 }
550
551 /**
552 * Removes a GNSS navigation message listener.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700553 */
554 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
Sasha Kuznetsovb9f26b42019-10-03 17:30:46 -0700555 synchronized (mGnssNavigationMessageListeners) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800556 removeGnssDataListenerLocked(
Sasha Kuznetsovb9f26b42019-10-03 17:30:46 -0700557 listener, mGnssNavigationMessageProvider, mGnssNavigationMessageListeners);
558 }
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700559 }
560
561 /**
562 * Send Ni Response, indicating a location request initiated by a network carrier.
563 */
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800564 public void sendNiResponse(int notifId, int userResponse) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700565 try {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800566 mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700567 } catch (RemoteException e) {
568 Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700569 }
570 }
571
572 /**
573 * Report location results to GNSS batching listener.
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700574 */
575 public void onReportLocation(List<Location> locations) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800576 IBatchedLocationCallback gnssBatchingCallback;
577 synchronized (mGnssBatchingLock) {
578 gnssBatchingCallback = mGnssBatchingCallback;
579 }
580
581 if (gnssBatchingCallback == null) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700582 return;
583 }
584
585 try {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800586 gnssBatchingCallback.onLocationBatch(locations);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700587 } catch (RemoteException e) {
588 Log.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
589 }
590 }
591
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800592 private boolean isThrottlingExempt(CallerIdentity callerIdentity) {
593 if (callerIdentity.mUid == Process.SYSTEM_UID) {
594 return true;
595 }
596
597 if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
598 callerIdentity.mPackageName)) {
599 return true;
600 }
601
602 synchronized (this) {
603 Preconditions.checkState(mLocationManagerInternal != null);
604 }
605 return mLocationManagerInternal.isProviderPackage(callerIdentity.mPackageName);
606 }
607
608 private boolean checkLocationAppOp(String packageName) {
609 synchronized (this) {
610 Preconditions.checkState(mAppOpsManager != null);
611 }
612 return mAppOpsManager.checkOp(OP_FINE_LOCATION, Binder.getCallingUid(), packageName)
613 == AppOpsManager.MODE_ALLOWED;
614 }
615
Soonil Nagarkarf20d10e2020-01-27 11:05:40 -0800616 /**
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800617 * Dump info for debugging.
Soonil Nagarkarf20d10e2020-01-27 11:05:40 -0800618 */
619 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700620 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
621
622 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
623 if (mGnssMetricsProvider != null) {
624 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
625 }
626 return;
627 }
628
629 ipw.println("GnssMeasurement Listeners:");
630 ipw.increaseIndent();
631 synchronized (mGnssMeasurementsListeners) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800632 for (LinkedListenerBase listener : mGnssMeasurementsListeners.values()) {
633 ipw.println(listener);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700634 }
635 }
636 ipw.decreaseIndent();
637
638 ipw.println("GnssNavigationMessage Listeners:");
639 ipw.increaseIndent();
640 synchronized (mGnssNavigationMessageListeners) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800641 for (LinkedListenerBase listener : mGnssNavigationMessageListeners.values()) {
642 ipw.println(listener);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700643 }
644 }
645 ipw.decreaseIndent();
646
647 ipw.println("GnssStatus Listeners:");
648 ipw.increaseIndent();
649 synchronized (mGnssStatusListeners) {
Soonil Nagarkarb6375a42020-01-29 15:23:06 -0800650 for (LinkedListenerBase listener : mGnssStatusListeners.values()) {
651 ipw.println(listener);
Sasha Kuznetsova8ace3c2019-09-13 14:14:40 -0700652 }
653 }
654 ipw.decreaseIndent();
655
656 synchronized (mGnssBatchingLock) {
657 if (mGnssBatchingInProgress) {
658 ipw.println("GNSS batching in progress");
659 }
660 }
661 }
662}