• 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.provider;
18 
19 import static android.app.compat.CompatChanges.isChangeEnabled;
20 import static android.location.LocationManager.DELIVER_HISTORICAL_LOCATIONS;
21 import static android.location.LocationManager.GPS_PROVIDER;
22 import static android.location.LocationManager.KEY_FLUSH_COMPLETE;
23 import static android.location.LocationManager.KEY_LOCATIONS;
24 import static android.location.LocationManager.KEY_LOCATION_CHANGED;
25 import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
26 import static android.location.LocationManager.PASSIVE_PROVIDER;
27 import static android.os.IPowerManager.LOCATION_MODE_NO_CHANGE;
28 import static android.os.PowerExemptionManager.REASON_LOCATION_PROVIDER;
29 import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
30 import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
31 import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
32 import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
33 import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
34 
35 import static com.android.server.location.LocationManagerService.D;
36 import static com.android.server.location.LocationManagerService.TAG;
37 import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
38 import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
39 import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
40 import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG;
41 
42 import static java.lang.Math.max;
43 import static java.lang.Math.min;
44 
45 import android.annotation.IntDef;
46 import android.annotation.Nullable;
47 import android.app.AlarmManager.OnAlarmListener;
48 import android.app.BroadcastOptions;
49 import android.app.PendingIntent;
50 import android.content.Context;
51 import android.content.Intent;
52 import android.location.ILocationCallback;
53 import android.location.ILocationListener;
54 import android.location.LastLocationRequest;
55 import android.location.Location;
56 import android.location.LocationManager;
57 import android.location.LocationManagerInternal;
58 import android.location.LocationManagerInternal.ProviderEnabledListener;
59 import android.location.LocationRequest;
60 import android.location.LocationResult;
61 import android.location.provider.IProviderRequestListener;
62 import android.location.provider.ProviderProperties;
63 import android.location.provider.ProviderRequest;
64 import android.location.util.identity.CallerIdentity;
65 import android.os.Binder;
66 import android.os.Build;
67 import android.os.Bundle;
68 import android.os.CancellationSignal;
69 import android.os.IBinder;
70 import android.os.ICancellationSignal;
71 import android.os.IRemoteCallback;
72 import android.os.PowerManager;
73 import android.os.PowerManager.LocationPowerSaveMode;
74 import android.os.Process;
75 import android.os.RemoteException;
76 import android.os.SystemClock;
77 import android.os.UserHandle;
78 import android.os.WorkSource;
79 import android.stats.location.LocationStatsEnums;
80 import android.text.TextUtils;
81 import android.util.ArraySet;
82 import android.util.EventLog;
83 import android.util.IndentingPrintWriter;
84 import android.util.Log;
85 import android.util.SparseArray;
86 import android.util.SparseBooleanArray;
87 import android.util.TimeUtils;
88 
89 import com.android.internal.annotations.GuardedBy;
90 import com.android.internal.util.Preconditions;
91 import com.android.server.FgThread;
92 import com.android.server.LocalServices;
93 import com.android.server.location.LocationPermissions;
94 import com.android.server.location.LocationPermissions.PermissionLevel;
95 import com.android.server.location.fudger.LocationFudger;
96 import com.android.server.location.injector.AlarmHelper;
97 import com.android.server.location.injector.AppForegroundHelper;
98 import com.android.server.location.injector.AppForegroundHelper.AppForegroundListener;
99 import com.android.server.location.injector.AppOpsHelper;
100 import com.android.server.location.injector.Injector;
101 import com.android.server.location.injector.LocationAttributionHelper;
102 import com.android.server.location.injector.LocationPermissionsHelper;
103 import com.android.server.location.injector.LocationPermissionsHelper.LocationPermissionsListener;
104 import com.android.server.location.injector.LocationPowerSaveModeHelper;
105 import com.android.server.location.injector.LocationPowerSaveModeHelper.LocationPowerSaveModeChangedListener;
106 import com.android.server.location.injector.LocationUsageLogger;
107 import com.android.server.location.injector.ScreenInteractiveHelper;
108 import com.android.server.location.injector.ScreenInteractiveHelper.ScreenInteractiveChangedListener;
109 import com.android.server.location.injector.SettingsHelper;
110 import com.android.server.location.injector.SettingsHelper.GlobalSettingChangedListener;
111 import com.android.server.location.injector.SettingsHelper.UserSettingChangedListener;
112 import com.android.server.location.injector.UserInfoHelper;
113 import com.android.server.location.injector.UserInfoHelper.UserListener;
114 import com.android.server.location.listeners.ListenerMultiplexer;
115 import com.android.server.location.listeners.RemoteListenerRegistration;
116 import com.android.server.location.settings.LocationSettings;
117 import com.android.server.location.settings.LocationUserSettings;
118 
119 import java.io.FileDescriptor;
120 import java.lang.annotation.Retention;
121 import java.lang.annotation.RetentionPolicy;
122 import java.util.ArrayList;
123 import java.util.Collection;
124 import java.util.Objects;
125 import java.util.concurrent.CopyOnWriteArrayList;
126 import java.util.function.Predicate;
127 
128 /**
129  * Manages all aspects of a single location provider.
130  */
131 public class LocationProviderManager extends
132         ListenerMultiplexer<Object, LocationProviderManager.LocationTransport,
133                 LocationProviderManager.Registration, ProviderRequest> implements
134         AbstractLocationProvider.Listener {
135 
136     private static final String WAKELOCK_TAG = "*location*";
137     private static final long WAKELOCK_TIMEOUT_MS = 30 * 1000;
138 
139     // duration PI location clients are put on the allowlist to start a fg service
140     private static final long TEMPORARY_APP_ALLOWLIST_DURATION_MS = 10 * 1000;
141 
142     // fastest interval at which clients may receive coarse locations
143     private static final long MIN_COARSE_INTERVAL_MS = 10 * 60 * 1000;
144 
145     // max interval to be considered "high power" request
146     private static final long MAX_HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
147 
148     // max age of a location before it is no longer considered "current"
149     private static final long MAX_CURRENT_LOCATION_AGE_MS = 30 * 1000;
150 
151     // max timeout allowed for getting the current location
152     private static final long MAX_GET_CURRENT_LOCATION_TIMEOUT_MS = 30 * 1000;
153 
154     // max jitter allowed for min update interval as a percentage of the interval
155     private static final float FASTEST_INTERVAL_JITTER_PERCENTAGE = .10f;
156 
157     // max absolute jitter allowed for min update interval evaluation
158     private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 30 * 1000;
159 
160     // minimum amount of request delay in order to respect the delay, below this value the request
161     // will just be scheduled immediately
162     private static final long MIN_REQUEST_DELAY_MS = 30 * 1000;
163 
164     @Retention(RetentionPolicy.SOURCE)
165     @IntDef({STATE_STARTED, STATE_STOPPING, STATE_STOPPED})
166     private @interface State {}
167 
168     private static final int STATE_STARTED = 0;
169     private static final int STATE_STOPPING = 1;
170     private static final int STATE_STOPPED = 2;
171 
172     public interface StateChangedListener {
onStateChanged(String provider, AbstractLocationProvider.State oldState, AbstractLocationProvider.State newState)173         void onStateChanged(String provider, AbstractLocationProvider.State oldState,
174                 AbstractLocationProvider.State newState);
175     }
176 
177     protected interface LocationTransport {
178 
deliverOnLocationChanged(LocationResult locationResult, @Nullable Runnable onCompleteCallback)179         void deliverOnLocationChanged(LocationResult locationResult,
180                 @Nullable Runnable onCompleteCallback) throws Exception;
deliverOnFlushComplete(int requestCode)181         void deliverOnFlushComplete(int requestCode) throws Exception;
182     }
183 
184     protected interface ProviderTransport {
185 
deliverOnProviderEnabledChanged(String provider, boolean enabled)186         void deliverOnProviderEnabledChanged(String provider, boolean enabled) throws Exception;
187     }
188 
189     protected static final class LocationListenerTransport implements LocationTransport,
190             ProviderTransport {
191 
192         private final ILocationListener mListener;
193 
LocationListenerTransport(ILocationListener listener)194         protected LocationListenerTransport(ILocationListener listener) {
195             mListener = Objects.requireNonNull(listener);
196         }
197 
198         @Override
deliverOnLocationChanged(LocationResult locationResult, @Nullable Runnable onCompleteCallback)199         public void deliverOnLocationChanged(LocationResult locationResult,
200                 @Nullable Runnable onCompleteCallback) throws RemoteException {
201             mListener.onLocationChanged(locationResult.asList(),
202                     SingleUseCallback.wrap(onCompleteCallback));
203         }
204 
205         @Override
deliverOnFlushComplete(int requestCode)206         public void deliverOnFlushComplete(int requestCode) throws RemoteException {
207             mListener.onFlushComplete(requestCode);
208         }
209 
210         @Override
deliverOnProviderEnabledChanged(String provider, boolean enabled)211         public void deliverOnProviderEnabledChanged(String provider, boolean enabled)
212                 throws RemoteException {
213             mListener.onProviderEnabledChanged(provider, enabled);
214         }
215     }
216 
217     protected static final class LocationPendingIntentTransport implements LocationTransport,
218             ProviderTransport {
219 
220         private final Context mContext;
221         private final PendingIntent mPendingIntent;
222 
LocationPendingIntentTransport(Context context, PendingIntent pendingIntent)223         public LocationPendingIntentTransport(Context context, PendingIntent pendingIntent) {
224             mContext = context;
225             mPendingIntent = pendingIntent;
226         }
227 
228         @Override
deliverOnLocationChanged(LocationResult locationResult, @Nullable Runnable onCompleteCallback)229         public void deliverOnLocationChanged(LocationResult locationResult,
230                 @Nullable Runnable onCompleteCallback)
231                 throws PendingIntent.CanceledException {
232             BroadcastOptions options = BroadcastOptions.makeBasic();
233             options.setDontSendToRestrictedApps(true);
234             // allows apps to start a fg service in response to a location PI
235             options.setTemporaryAppAllowlist(TEMPORARY_APP_ALLOWLIST_DURATION_MS,
236                     TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
237                     REASON_LOCATION_PROVIDER,
238                     "");
239 
240             Intent intent = new Intent().putExtra(KEY_LOCATION_CHANGED,
241                     locationResult.getLastLocation());
242             if (locationResult.size() > 1) {
243                 intent.putExtra(KEY_LOCATIONS, locationResult.asList().toArray(new Location[0]));
244             }
245 
246             mPendingIntent.send(
247                     mContext,
248                     0,
249                     intent,
250                     onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run()
251                             : null,
252                     null,
253                     null,
254                     options.toBundle());
255         }
256 
257         @Override
deliverOnFlushComplete(int requestCode)258         public void deliverOnFlushComplete(int requestCode) throws PendingIntent.CanceledException {
259             BroadcastOptions options = BroadcastOptions.makeBasic();
260             options.setDontSendToRestrictedApps(true);
261 
262             mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_FLUSH_COMPLETE, requestCode),
263                     null, null, null, options.toBundle());
264         }
265 
266         @Override
deliverOnProviderEnabledChanged(String provider, boolean enabled)267         public void deliverOnProviderEnabledChanged(String provider, boolean enabled)
268                 throws PendingIntent.CanceledException {
269             BroadcastOptions options = BroadcastOptions.makeBasic();
270             options.setDontSendToRestrictedApps(true);
271 
272             mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_PROVIDER_ENABLED, enabled),
273                     null, null, null, options.toBundle());
274         }
275     }
276 
277     protected static final class GetCurrentLocationTransport implements LocationTransport {
278 
279         private final ILocationCallback mCallback;
280 
GetCurrentLocationTransport(ILocationCallback callback)281         protected GetCurrentLocationTransport(ILocationCallback callback) {
282             mCallback = Objects.requireNonNull(callback);
283         }
284 
285         @Override
deliverOnLocationChanged(@ullable LocationResult locationResult, @Nullable Runnable onCompleteCallback)286         public void deliverOnLocationChanged(@Nullable LocationResult locationResult,
287                 @Nullable Runnable onCompleteCallback)
288                 throws RemoteException {
289             // ILocationCallback doesn't currently support completion callbacks
290             Preconditions.checkState(onCompleteCallback == null);
291             if (locationResult != null) {
292                 mCallback.onLocation(locationResult.getLastLocation());
293             } else {
294                 mCallback.onLocation(null);
295             }
296         }
297 
298         @Override
deliverOnFlushComplete(int requestCode)299         public void deliverOnFlushComplete(int requestCode) {}
300     }
301 
302     protected abstract class Registration extends RemoteListenerRegistration<LocationRequest,
303             LocationTransport> {
304 
305         private final @PermissionLevel int mPermissionLevel;
306 
307         // we cache these values because checking/calculating on the fly is more expensive
308         private boolean mPermitted;
309         private boolean mForeground;
310         private LocationRequest mProviderLocationRequest;
311         private boolean mIsUsingHighPower;
312 
313         private @Nullable Location mLastLocation = null;
314 
Registration(LocationRequest request, CallerIdentity identity, LocationTransport transport, @PermissionLevel int permissionLevel)315         protected Registration(LocationRequest request, CallerIdentity identity,
316                 LocationTransport transport, @PermissionLevel int permissionLevel) {
317             super(Objects.requireNonNull(request), identity, transport);
318 
319             Preconditions.checkArgument(identity.getListenerId() != null);
320             Preconditions.checkArgument(permissionLevel > PERMISSION_NONE);
321             Preconditions.checkArgument(!request.getWorkSource().isEmpty());
322 
323             mPermissionLevel = permissionLevel;
324             mProviderLocationRequest = request;
325         }
326 
327         @GuardedBy("mLock")
328         @Override
onRemovableListenerRegister()329         protected final void onRemovableListenerRegister() {
330             if (Build.IS_DEBUGGABLE) {
331                 Preconditions.checkState(Thread.holdsLock(mLock));
332             }
333 
334             if (D) {
335                 Log.d(TAG, mName + " provider added registration from " + getIdentity() + " -> "
336                         + getRequest());
337             }
338 
339             EVENT_LOG.logProviderClientRegistered(mName, getIdentity(), super.getRequest());
340 
341             // initialization order is important as there are ordering dependencies
342             mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
343                     getIdentity());
344             mForeground = mAppForegroundHelper.isAppForeground(getIdentity().getUid());
345             mProviderLocationRequest = calculateProviderLocationRequest();
346             mIsUsingHighPower = isUsingHighPower();
347 
348             onProviderListenerRegister();
349 
350             if (mForeground) {
351                 EVENT_LOG.logProviderClientForeground(mName, getIdentity());
352             }
353         }
354 
355         @GuardedBy("mLock")
356         @Override
onRemovableListenerUnregister()357         protected final void onRemovableListenerUnregister() {
358             if (Build.IS_DEBUGGABLE) {
359                 Preconditions.checkState(Thread.holdsLock(mLock));
360             }
361 
362             onProviderListenerUnregister();
363 
364             EVENT_LOG.logProviderClientUnregistered(mName, getIdentity());
365 
366             if (D) {
367                 Log.d(TAG, mName + " provider removed registration from " + getIdentity());
368             }
369         }
370 
371         /**
372          * Subclasses may override this instead of {@link #onRemovableListenerRegister()}.
373          */
374         @GuardedBy("mLock")
onProviderListenerRegister()375         protected void onProviderListenerRegister() {}
376 
377         /**
378          * Subclasses may override this instead of {@link #onRemovableListenerUnregister()}.
379          */
380         @GuardedBy("mLock")
onProviderListenerUnregister()381         protected void onProviderListenerUnregister() {}
382 
383         @Override
onActive()384         protected final void onActive() {
385             if (Build.IS_DEBUGGABLE) {
386                 Preconditions.checkState(Thread.holdsLock(mLock));
387             }
388 
389             EVENT_LOG.logProviderClientActive(mName, getIdentity());
390 
391             if (!getRequest().isHiddenFromAppOps()) {
392                 mLocationAttributionHelper.reportLocationStart(getIdentity(), getName(), getKey());
393             }
394             onHighPowerUsageChanged();
395 
396             onProviderListenerActive();
397         }
398 
399         @Override
onInactive()400         protected final void onInactive() {
401             if (Build.IS_DEBUGGABLE) {
402                 Preconditions.checkState(Thread.holdsLock(mLock));
403             }
404 
405             onHighPowerUsageChanged();
406             if (!getRequest().isHiddenFromAppOps()) {
407                 mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
408             }
409 
410             onProviderListenerInactive();
411 
412             EVENT_LOG.logProviderClientInactive(mName, getIdentity());
413         }
414 
415         /**
416          * Subclasses may override this instead of {@link #onActive()}.
417          */
418         @GuardedBy("mLock")
onProviderListenerActive()419         protected void onProviderListenerActive() {}
420 
421         /**
422          * Subclasses may override this instead of {@link #onInactive()} ()}.
423          */
424         @GuardedBy("mLock")
onProviderListenerInactive()425         protected void onProviderListenerInactive() {}
426 
427         @Override
getRequest()428         public final LocationRequest getRequest() {
429             return mProviderLocationRequest;
430         }
431 
432         @GuardedBy("mLock")
setLastDeliveredLocation(@ullable Location location)433         final void setLastDeliveredLocation(@Nullable Location location) {
434             mLastLocation = location;
435         }
436 
437         @GuardedBy("mLock")
getLastDeliveredLocation()438         public final Location getLastDeliveredLocation() {
439             return mLastLocation;
440         }
441 
getPermissionLevel()442         public @PermissionLevel int getPermissionLevel() {
443             return mPermissionLevel;
444         }
445 
isForeground()446         public final boolean isForeground() {
447             return mForeground;
448         }
449 
isPermitted()450         public final boolean isPermitted() {
451             return mPermitted;
452         }
453 
flush(int requestCode)454         public final void flush(int requestCode) {
455             // when the flush callback is invoked, we are guaranteed that locations have been
456             // queued on our executor, so by running the listener callback on the same executor it
457             // should be guaranteed that those locations will be delivered before the flush callback
458             mProvider.getController().flush(() -> executeOperation(
459                     listener -> listener.deliverOnFlushComplete(requestCode)));
460         }
461 
462         @Override
getOwner()463         protected final LocationProviderManager getOwner() {
464             return LocationProviderManager.this;
465         }
466 
467         @GuardedBy("mLock")
onProviderPropertiesChanged()468         final boolean onProviderPropertiesChanged() {
469             onHighPowerUsageChanged();
470             return false;
471         }
472 
473         @GuardedBy("mLock")
onHighPowerUsageChanged()474         private void onHighPowerUsageChanged() {
475             boolean isUsingHighPower = isUsingHighPower();
476             if (isUsingHighPower != mIsUsingHighPower) {
477                 mIsUsingHighPower = isUsingHighPower;
478 
479                 if (!getRequest().isHiddenFromAppOps()) {
480                     if (mIsUsingHighPower) {
481                         mLocationAttributionHelper.reportHighPowerLocationStart(
482                                 getIdentity(), getName(), getKey());
483                     } else {
484                         mLocationAttributionHelper.reportHighPowerLocationStop(
485                                 getIdentity(), getName(), getKey());
486                     }
487                 }
488             }
489         }
490 
491         @GuardedBy("mLock")
isUsingHighPower()492         private boolean isUsingHighPower() {
493             if (Build.IS_DEBUGGABLE) {
494                 Preconditions.checkState(Thread.holdsLock(mLock));
495             }
496 
497             ProviderProperties properties = getProperties();
498             if (properties == null) {
499                 return false;
500             }
501 
502             return isActive()
503                     && getRequest().getIntervalMillis() < MAX_HIGH_POWER_INTERVAL_MS
504                     && properties.getPowerUsage() == ProviderProperties.POWER_USAGE_HIGH;
505         }
506 
507         @GuardedBy("mLock")
onLocationPermissionsChanged(String packageName)508         final boolean onLocationPermissionsChanged(String packageName) {
509             if (getIdentity().getPackageName().equals(packageName)) {
510                 return onLocationPermissionsChanged();
511             }
512 
513             return false;
514         }
515 
516         @GuardedBy("mLock")
onLocationPermissionsChanged(int uid)517         final boolean onLocationPermissionsChanged(int uid) {
518             if (getIdentity().getUid() == uid) {
519                 return onLocationPermissionsChanged();
520             }
521 
522             return false;
523         }
524 
525         @GuardedBy("mLock")
onLocationPermissionsChanged()526         private boolean onLocationPermissionsChanged() {
527             if (Build.IS_DEBUGGABLE) {
528                 Preconditions.checkState(Thread.holdsLock(mLock));
529             }
530 
531             boolean permitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
532                     getIdentity());
533             if (permitted != mPermitted) {
534                 if (D) {
535                     Log.v(TAG, mName + " provider package " + getIdentity().getPackageName()
536                             + " permitted = " + permitted);
537                 }
538 
539                 mPermitted = permitted;
540 
541                 if (mPermitted) {
542                     EVENT_LOG.logProviderClientPermitted(mName, getIdentity());
543                 } else {
544                     EVENT_LOG.logProviderClientUnpermitted(mName, getIdentity());
545                 }
546 
547                 return true;
548             }
549 
550             return false;
551         }
552 
553         @GuardedBy("mLock")
onAdasGnssLocationEnabledChanged(int userId)554         final boolean onAdasGnssLocationEnabledChanged(int userId) {
555             if (Build.IS_DEBUGGABLE) {
556                 Preconditions.checkState(Thread.holdsLock(mLock));
557             }
558 
559             if (getIdentity().getUserId() == userId) {
560                 return onProviderLocationRequestChanged();
561             }
562 
563             return false;
564         }
565 
566         @GuardedBy("mLock")
onForegroundChanged(int uid, boolean foreground)567         final boolean onForegroundChanged(int uid, boolean foreground) {
568             if (Build.IS_DEBUGGABLE) {
569                 Preconditions.checkState(Thread.holdsLock(mLock));
570             }
571 
572             if (getIdentity().getUid() == uid && foreground != mForeground) {
573                 if (D) {
574                     Log.v(TAG, mName + " provider uid " + uid + " foreground = " + foreground);
575                 }
576 
577                 mForeground = foreground;
578 
579                 if (mForeground) {
580                     EVENT_LOG.logProviderClientForeground(mName, getIdentity());
581                 } else {
582                     EVENT_LOG.logProviderClientBackground(mName, getIdentity());
583                 }
584 
585                 // note that onProviderLocationRequestChanged() is always called
586                 return onProviderLocationRequestChanged()
587                         || mLocationPowerSaveModeHelper.getLocationPowerSaveMode()
588                         == LOCATION_MODE_FOREGROUND_ONLY;
589             }
590 
591             return false;
592         }
593 
594         @GuardedBy("mLock")
onProviderLocationRequestChanged()595         final boolean onProviderLocationRequestChanged() {
596             if (Build.IS_DEBUGGABLE) {
597                 Preconditions.checkState(Thread.holdsLock(mLock));
598             }
599 
600             LocationRequest newRequest = calculateProviderLocationRequest();
601             if (mProviderLocationRequest.equals(newRequest)) {
602                 return false;
603             }
604 
605             LocationRequest oldRequest = mProviderLocationRequest;
606             mProviderLocationRequest = newRequest;
607             onHighPowerUsageChanged();
608             updateService();
609 
610             // if bypass state has changed then the active state may have changed
611             return oldRequest.isBypass() != newRequest.isBypass();
612         }
613 
calculateProviderLocationRequest()614         private LocationRequest calculateProviderLocationRequest() {
615             LocationRequest baseRequest = super.getRequest();
616             LocationRequest.Builder builder = new LocationRequest.Builder(baseRequest);
617 
618             if (mPermissionLevel < PERMISSION_FINE) {
619                 builder.setQuality(LocationRequest.QUALITY_LOW_POWER);
620                 if (baseRequest.getIntervalMillis() < MIN_COARSE_INTERVAL_MS) {
621                     builder.setIntervalMillis(MIN_COARSE_INTERVAL_MS);
622                 }
623                 if (baseRequest.getMinUpdateIntervalMillis() < MIN_COARSE_INTERVAL_MS) {
624                     builder.setMinUpdateIntervalMillis(MIN_COARSE_INTERVAL_MS);
625                 }
626             }
627 
628             boolean locationSettingsIgnored = baseRequest.isLocationSettingsIgnored();
629             if (locationSettingsIgnored) {
630                 // if we are not currently allowed use location settings ignored, disable it
631                 if (!mSettingsHelper.getIgnoreSettingsAllowlist().contains(
632                         getIdentity().getPackageName(), getIdentity().getAttributionTag())
633                         && !mLocationManagerInternal.isProvider(null, getIdentity())) {
634                     locationSettingsIgnored = false;
635                 }
636 
637                 builder.setLocationSettingsIgnored(locationSettingsIgnored);
638             }
639 
640             boolean adasGnssBypass = baseRequest.isAdasGnssBypass();
641             if (adasGnssBypass) {
642                 // if we are not currently allowed use adas gnss bypass, disable it
643                 if (!GPS_PROVIDER.equals(mName)) {
644                     Log.e(TAG, "adas gnss bypass request received in non-gps provider");
645                     adasGnssBypass = false;
646                 } else if (!mLocationSettings.getUserSettings(
647                         getIdentity().getUserId()).isAdasGnssLocationEnabled()) {
648                     adasGnssBypass = false;
649                 }
650 
651                 builder.setAdasGnssBypass(adasGnssBypass);
652             }
653 
654             if (!locationSettingsIgnored && !isThrottlingExempt()) {
655                 // throttle in the background
656                 if (!mForeground) {
657                     builder.setIntervalMillis(max(baseRequest.getIntervalMillis(),
658                             mSettingsHelper.getBackgroundThrottleIntervalMs()));
659                 }
660             }
661 
662             return builder.build();
663         }
664 
isThrottlingExempt()665         private boolean isThrottlingExempt() {
666             if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
667                     getIdentity().getPackageName())) {
668                 return true;
669             }
670 
671             return mLocationManagerInternal.isProvider(null, getIdentity());
672         }
673 
674         @GuardedBy("mLock")
acceptLocationChange( LocationResult fineLocationResult)675         abstract @Nullable ListenerOperation<LocationTransport> acceptLocationChange(
676                 LocationResult fineLocationResult);
677 
678         @Override
toString()679         public String toString() {
680             StringBuilder builder = new StringBuilder();
681             builder.append(getIdentity());
682 
683             ArraySet<String> flags = new ArraySet<>(2);
684             if (!isForeground()) {
685                 flags.add("bg");
686             }
687             if (!isPermitted()) {
688                 flags.add("na");
689             }
690             if (!flags.isEmpty()) {
691                 builder.append(" ").append(flags);
692             }
693 
694             if (mPermissionLevel == PERMISSION_COARSE) {
695                 builder.append(" (COARSE)");
696             }
697 
698             builder.append(" ").append(getRequest());
699             return builder.toString();
700         }
701     }
702 
703     protected abstract class LocationRegistration extends Registration implements
704             OnAlarmListener, ProviderEnabledListener {
705 
706         final PowerManager.WakeLock mWakeLock;
707 
708         private volatile ProviderTransport mProviderTransport;
709         private int mNumLocationsDelivered = 0;
710         private long mExpirationRealtimeMs = Long.MAX_VALUE;
711 
LocationRegistration( LocationRequest request, CallerIdentity identity, TTransport transport, @PermissionLevel int permissionLevel)712         protected <TTransport extends LocationTransport & ProviderTransport> LocationRegistration(
713                 LocationRequest request, CallerIdentity identity, TTransport transport,
714                 @PermissionLevel int permissionLevel) {
715             super(request, identity, transport, permissionLevel);
716             mProviderTransport = transport;
717             mWakeLock = Objects.requireNonNull(mContext.getSystemService(PowerManager.class))
718                     .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
719             mWakeLock.setReferenceCounted(true);
720             mWakeLock.setWorkSource(request.getWorkSource());
721         }
722 
723         @Override
onListenerUnregister()724         protected void onListenerUnregister() {
725             mProviderTransport = null;
726         }
727 
728         @GuardedBy("mLock")
729         @Override
onProviderListenerRegister()730         protected final void onProviderListenerRegister() {
731             long registerTimeMs = SystemClock.elapsedRealtime();
732             mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(registerTimeMs);
733 
734             // add alarm for expiration
735             if (mExpirationRealtimeMs <= registerTimeMs) {
736                 onAlarm();
737             } else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
738                 // Set WorkSource to null in order to ensure the alarm wakes up the device even when
739                 // it is idle. Do this when the cost of waking up the device is less than the power
740                 // cost of not performing the actions set off by the alarm, such as unregistering a
741                 // location request.
742                 mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this,
743                         null);
744             }
745 
746             // start listening for provider enabled/disabled events
747             addEnabledListener(this);
748 
749             onLocationListenerRegister();
750 
751             // if the provider is currently disabled, let the client know immediately
752             int userId = getIdentity().getUserId();
753             if (!isEnabled(userId)) {
754                 onProviderEnabledChanged(mName, userId, false);
755             }
756         }
757 
758         @GuardedBy("mLock")
759         @Override
onProviderListenerUnregister()760         protected final void onProviderListenerUnregister() {
761             // stop listening for provider enabled/disabled events
762             removeEnabledListener(this);
763 
764             // remove alarm for expiration
765             if (mExpirationRealtimeMs < Long.MAX_VALUE) {
766                 mAlarmHelper.cancel(this);
767             }
768 
769             onLocationListenerUnregister();
770         }
771 
772         /**
773          * Subclasses may override this instead of {@link #onRemovableListenerRegister()}.
774          */
775         @GuardedBy("mLock")
onLocationListenerRegister()776         protected void onLocationListenerRegister() {}
777 
778         /**
779          * Subclasses may override this instead of {@link #onRemovableListenerUnregister()}.
780          */
781         @GuardedBy("mLock")
onLocationListenerUnregister()782         protected void onLocationListenerUnregister() {}
783 
784         @GuardedBy("mLock")
785         @Override
onProviderListenerActive()786         protected final void onProviderListenerActive() {
787             // a new registration may not get a location immediately, the provider request may be
788             // delayed. therefore we deliver a historical location if available. since delivering an
789             // older location could be considered a breaking change for some applications, we only
790             // do so for apps targeting S+.
791             if (isChangeEnabled(DELIVER_HISTORICAL_LOCATIONS, getIdentity().getUid())) {
792                 long maxLocationAgeMs = getRequest().getIntervalMillis();
793                 Location lastDeliveredLocation = getLastDeliveredLocation();
794                 if (lastDeliveredLocation != null) {
795                     // ensure that location is fresher than the last delivered location
796                     maxLocationAgeMs = min(maxLocationAgeMs,
797                             lastDeliveredLocation.getElapsedRealtimeAgeMillis() - 1);
798                 }
799 
800                 // requests are never delayed less than MIN_REQUEST_DELAY_MS, so it only makes sense
801                 // to deliver historical locations to clients with a last location older than that
802                 if (maxLocationAgeMs > MIN_REQUEST_DELAY_MS) {
803                     Location lastLocation = getLastLocationUnsafe(
804                             getIdentity().getUserId(),
805                             getPermissionLevel(),
806                             getRequest().isBypass(),
807                             maxLocationAgeMs);
808                     if (lastLocation != null) {
809                         executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
810                     }
811                 }
812             }
813         }
814 
815         @Override
onAlarm()816         public void onAlarm() {
817             if (D) {
818                 Log.d(TAG, mName + " provider registration " + getIdentity()
819                         + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
820             }
821 
822             synchronized (mLock) {
823                 // no need to remove alarm after it's fired
824                 mExpirationRealtimeMs = Long.MAX_VALUE;
825                 remove();
826             }
827         }
828 
829         @GuardedBy("mLock")
830         @Override
acceptLocationChange( LocationResult fineLocationResult)831         @Nullable ListenerOperation<LocationTransport> acceptLocationChange(
832                 LocationResult fineLocationResult) {
833             if (Build.IS_DEBUGGABLE) {
834                 Preconditions.checkState(Thread.holdsLock(mLock));
835             }
836 
837             // check expiration time - alarm is not guaranteed to go off at the right time,
838             // especially for short intervals
839             if (SystemClock.elapsedRealtime() >= mExpirationRealtimeMs) {
840                 if (D) {
841                     Log.d(TAG, mName + " provider registration " + getIdentity()
842                             + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
843                 }
844                 remove();
845                 return null;
846             }
847 
848             LocationResult permittedLocationResult = Objects.requireNonNull(
849                     getPermittedLocationResult(fineLocationResult, getPermissionLevel()));
850 
851             LocationResult locationResult = permittedLocationResult.filter(
852                     new Predicate<Location>() {
853                         private Location mPreviousLocation = getLastDeliveredLocation();
854 
855                         @Override
856                         public boolean test(Location location) {
857                             if (mPreviousLocation != null) {
858                                 // check fastest interval
859                                 long deltaMs = location.getElapsedRealtimeMillis()
860                                         - mPreviousLocation.getElapsedRealtimeMillis();
861                                 long maxJitterMs = min((long) (FASTEST_INTERVAL_JITTER_PERCENTAGE
862                                                 * getRequest().getIntervalMillis()),
863                                         MAX_FASTEST_INTERVAL_JITTER_MS);
864                                 if (deltaMs
865                                         < getRequest().getMinUpdateIntervalMillis() - maxJitterMs) {
866                                     return false;
867                                 }
868 
869                                 // check smallest displacement
870                                 double smallestDisplacementM =
871                                         getRequest().getMinUpdateDistanceMeters();
872                                 if (smallestDisplacementM > 0.0 && location.distanceTo(
873                                         mPreviousLocation)
874                                         <= smallestDisplacementM) {
875                                     return false;
876                                 }
877                             }
878 
879                             mPreviousLocation = location;
880                             return true;
881                         }
882                     });
883 
884             if (locationResult == null) {
885                 return null;
886             }
887 
888             // note app ops
889             if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(getPermissionLevel()),
890                     getIdentity())) {
891                 if (D) {
892                     Log.w(TAG, "noteOp denied for " + getIdentity());
893                 }
894                 return null;
895             }
896 
897             // deliver location
898             return new ListenerOperation<LocationTransport>() {
899 
900                 private boolean mUseWakeLock;
901 
902                 @Override
903                 public void onPreExecute() {
904                     mUseWakeLock = false;
905                     final int size = locationResult.size();
906                     for (int i = 0; i < size; ++i) {
907                         if (!locationResult.get(i).isMock()) {
908                             mUseWakeLock = true;
909                             break;
910                         }
911                     }
912 
913                     // update last delivered location
914                     setLastDeliveredLocation(locationResult.getLastLocation());
915 
916                     // don't acquire a wakelock for mock locations to prevent abuse
917                     if (mUseWakeLock) {
918                         mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
919                     }
920                 }
921 
922                 @Override
923                 public void operate(LocationTransport listener) throws Exception {
924                     // if delivering to the same process, make a copy of the location first (since
925                     // location is mutable)
926                     LocationResult deliverLocationResult;
927                     if (getIdentity().getPid() == Process.myPid()) {
928                         deliverLocationResult = locationResult.deepCopy();
929                     } else {
930                         deliverLocationResult = locationResult;
931                     }
932 
933                     listener.deliverOnLocationChanged(deliverLocationResult,
934                             mUseWakeLock ? mWakeLock::release : null);
935                     EVENT_LOG.logProviderDeliveredLocations(mName, locationResult.size(),
936                             getIdentity());
937                 }
938 
939                 @Override
940                 public void onPostExecute(boolean success) {
941                     if (!success && mUseWakeLock) {
942                         mWakeLock.release();
943                     }
944 
945                     if (success) {
946                         // check num updates - if successful then this function will always be run
947                         // from the same thread, and no additional synchronization is necessary
948                         boolean remove = ++mNumLocationsDelivered >= getRequest().getMaxUpdates();
949                         if (remove) {
950                             if (D) {
951                                 Log.d(TAG, mName + " provider registration " + getIdentity()
952                                         + " finished after " + mNumLocationsDelivered + " updates");
953                             }
954 
955                             synchronized (mLock) {
956                                 remove();
957                             }
958                         }
959                     }
960                 }
961             };
962         }
963 
964         @Override
onProviderEnabledChanged(String provider, int userId, boolean enabled)965         public void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
966             Preconditions.checkState(mName.equals(provider));
967 
968             if (userId != getIdentity().getUserId()) {
969                 return;
970             }
971 
972             // we choose not to hold a wakelock for provider enabled changed events
973             executeSafely(getExecutor(), () -> mProviderTransport,
974                     listener -> listener.deliverOnProviderEnabledChanged(mName, enabled),
975                     this::onProviderOperationFailure);
976         }
977 
onProviderOperationFailure( ListenerOperation<ProviderTransport> operation, Exception exception)978         protected abstract void onProviderOperationFailure(
979                 ListenerOperation<ProviderTransport> operation, Exception exception);
980     }
981 
982     protected final class LocationListenerRegistration extends LocationRegistration implements
983             IBinder.DeathRecipient {
984 
LocationListenerRegistration(LocationRequest request, CallerIdentity identity, LocationListenerTransport transport, @PermissionLevel int permissionLevel)985         protected LocationListenerRegistration(LocationRequest request, CallerIdentity identity,
986                 LocationListenerTransport transport, @PermissionLevel int permissionLevel) {
987             super(request, identity, transport, permissionLevel);
988         }
989 
990         @GuardedBy("mLock")
991         @Override
onLocationListenerRegister()992         protected void onLocationListenerRegister() {
993             try {
994                 ((IBinder) getKey()).linkToDeath(this, 0);
995             } catch (RemoteException e) {
996                 remove();
997             }
998         }
999 
1000         @GuardedBy("mLock")
1001         @Override
onLocationListenerUnregister()1002         protected void onLocationListenerUnregister() {
1003             ((IBinder) getKey()).unlinkToDeath(this, 0);
1004         }
1005 
1006         @Override
onProviderOperationFailure(ListenerOperation<ProviderTransport> operation, Exception exception)1007         protected void onProviderOperationFailure(ListenerOperation<ProviderTransport> operation,
1008                 Exception exception) {
1009             onTransportFailure(exception);
1010         }
1011 
1012         @Override
onOperationFailure(ListenerOperation<LocationTransport> operation, Exception exception)1013         public void onOperationFailure(ListenerOperation<LocationTransport> operation,
1014                 Exception exception) {
1015             onTransportFailure(exception);
1016         }
1017 
onTransportFailure(Exception e)1018         private void onTransportFailure(Exception e) {
1019             if (e instanceof RemoteException) {
1020                 Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
1021                 synchronized (mLock) {
1022                     remove();
1023                 }
1024             } else {
1025                 throw new AssertionError(e);
1026             }
1027         }
1028 
1029         @Override
binderDied()1030         public void binderDied() {
1031             try {
1032                 if (D) {
1033                     Log.d(TAG, mName + " provider registration " + getIdentity() + " died");
1034                 }
1035 
1036                 synchronized (mLock) {
1037                     remove();
1038                 }
1039             } catch (RuntimeException e) {
1040                 // the caller may swallow runtime exceptions, so we rethrow as assertion errors to
1041                 // ensure the crash is seen
1042                 throw new AssertionError(e);
1043             }
1044         }
1045     }
1046 
1047     protected final class LocationPendingIntentRegistration extends LocationRegistration implements
1048             PendingIntent.CancelListener {
1049 
LocationPendingIntentRegistration(LocationRequest request, CallerIdentity identity, LocationPendingIntentTransport transport, @PermissionLevel int permissionLevel)1050         protected LocationPendingIntentRegistration(LocationRequest request,
1051                 CallerIdentity identity, LocationPendingIntentTransport transport,
1052                 @PermissionLevel int permissionLevel) {
1053             super(request, identity, transport, permissionLevel);
1054         }
1055 
1056         @GuardedBy("mLock")
1057         @Override
onLocationListenerRegister()1058         protected void onLocationListenerRegister() {
1059             ((PendingIntent) getKey()).registerCancelListener(this);
1060         }
1061 
1062         @GuardedBy("mLock")
1063         @Override
onLocationListenerUnregister()1064         protected void onLocationListenerUnregister() {
1065             ((PendingIntent) getKey()).unregisterCancelListener(this);
1066         }
1067 
1068         @Override
onProviderOperationFailure(ListenerOperation<ProviderTransport> operation, Exception exception)1069         protected void onProviderOperationFailure(ListenerOperation<ProviderTransport> operation,
1070                 Exception exception) {
1071             onTransportFailure(exception);
1072         }
1073 
1074         @Override
onOperationFailure(ListenerOperation<LocationTransport> operation, Exception exception)1075         public void onOperationFailure(ListenerOperation<LocationTransport> operation,
1076                 Exception exception) {
1077             onTransportFailure(exception);
1078         }
1079 
onTransportFailure(Exception e)1080         private void onTransportFailure(Exception e) {
1081             if (e instanceof RemoteException) {
1082                 Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
1083                 synchronized (mLock) {
1084                     remove();
1085                 }
1086             } else {
1087                 throw new AssertionError(e);
1088             }
1089         }
1090 
1091         @Override
onCancelled(PendingIntent intent)1092         public void onCancelled(PendingIntent intent) {
1093             if (D) {
1094                 Log.d(TAG, mName + " provider registration " + getIdentity() + " cancelled");
1095             }
1096 
1097             synchronized (mLock) {
1098                 remove();
1099             }
1100         }
1101     }
1102 
1103     protected final class GetCurrentLocationListenerRegistration extends Registration implements
1104             IBinder.DeathRecipient, OnAlarmListener {
1105 
1106         private long mExpirationRealtimeMs = Long.MAX_VALUE;
1107 
GetCurrentLocationListenerRegistration(LocationRequest request, CallerIdentity identity, LocationTransport transport, int permissionLevel)1108         protected GetCurrentLocationListenerRegistration(LocationRequest request,
1109                 CallerIdentity identity, LocationTransport transport, int permissionLevel) {
1110             super(request, identity, transport, permissionLevel);
1111         }
1112 
1113         @GuardedBy("mLock")
1114         @Override
onProviderListenerRegister()1115         protected void onProviderListenerRegister() {
1116             try {
1117                 ((IBinder) getKey()).linkToDeath(this, 0);
1118             } catch (RemoteException e) {
1119                 remove();
1120             }
1121 
1122             long registerTimeMs = SystemClock.elapsedRealtime();
1123             mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(registerTimeMs);
1124 
1125             // add alarm for expiration
1126             if (mExpirationRealtimeMs <= registerTimeMs) {
1127                 onAlarm();
1128             } else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
1129                 // Set WorkSource to null in order to ensure the alarm wakes up the device even when
1130                 // it is idle. Do this when the cost of waking up the device is less than the power
1131                 // cost of not performing the actions set off by the alarm, such as unregistering a
1132                 // location request.
1133                 mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this,
1134                         null);
1135             }
1136         }
1137 
1138         @GuardedBy("mLock")
1139         @Override
onProviderListenerUnregister()1140         protected void onProviderListenerUnregister() {
1141             // remove alarm for expiration
1142             if (mExpirationRealtimeMs < Long.MAX_VALUE) {
1143                 mAlarmHelper.cancel(this);
1144             }
1145 
1146             ((IBinder) getKey()).unlinkToDeath(this, 0);
1147         }
1148 
1149         @GuardedBy("mLock")
1150         @Override
onProviderListenerActive()1151         protected void onProviderListenerActive() {
1152             Location lastLocation = getLastLocationUnsafe(
1153                     getIdentity().getUserId(),
1154                     getPermissionLevel(),
1155                     getRequest().isBypass(),
1156                     MAX_CURRENT_LOCATION_AGE_MS);
1157             if (lastLocation != null) {
1158                 executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
1159             }
1160         }
1161 
1162         @GuardedBy("mLock")
1163         @Override
onProviderListenerInactive()1164         protected void onProviderListenerInactive() {
1165             // if we go inactive for any reason, fail immediately
1166             executeOperation(acceptLocationChange(null));
1167         }
1168 
deliverNull()1169         void deliverNull() {
1170             synchronized (mLock) {
1171                 executeOperation(acceptLocationChange(null));
1172             }
1173         }
1174 
1175         @Override
onAlarm()1176         public void onAlarm() {
1177             if (D) {
1178                 Log.d(TAG, mName + " provider registration " + getIdentity()
1179                         + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
1180             }
1181 
1182             synchronized (mLock) {
1183                 // no need to remove alarm after it's fired
1184                 mExpirationRealtimeMs = Long.MAX_VALUE;
1185                 executeOperation(acceptLocationChange(null));
1186             }
1187         }
1188 
1189         @GuardedBy("mLock")
1190         @Override
acceptLocationChange( @ullable LocationResult fineLocationResult)1191         @Nullable ListenerOperation<LocationTransport> acceptLocationChange(
1192                 @Nullable LocationResult fineLocationResult) {
1193             if (Build.IS_DEBUGGABLE) {
1194                 Preconditions.checkState(Thread.holdsLock(mLock));
1195             }
1196 
1197             // check expiration time - alarm is not guaranteed to go off at the right time,
1198             // especially for short intervals
1199             if (SystemClock.elapsedRealtime() >= mExpirationRealtimeMs) {
1200                 if (D) {
1201                     Log.d(TAG, mName + " provider registration " + getIdentity()
1202                             + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
1203                 }
1204                 fineLocationResult = null;
1205             }
1206 
1207             // lastly - note app ops
1208             if (fineLocationResult != null && !mAppOpsHelper.noteOpNoThrow(
1209                     LocationPermissions.asAppOp(getPermissionLevel()), getIdentity())) {
1210                 if (D) {
1211                     Log.w(TAG, "noteOp denied for " + getIdentity());
1212                 }
1213                 fineLocationResult = null;
1214             }
1215 
1216             if (fineLocationResult != null) {
1217                 fineLocationResult = fineLocationResult.asLastLocationResult();
1218             }
1219 
1220             LocationResult locationResult = getPermittedLocationResult(fineLocationResult,
1221                     getPermissionLevel());
1222 
1223             // deliver location
1224             return new ListenerOperation<LocationTransport>() {
1225                 @Override
1226                 public void operate(LocationTransport listener) throws Exception {
1227                     // if delivering to the same process, make a copy of the location first (since
1228                     // location is mutable)
1229                     LocationResult deliverLocationResult;
1230                     if (getIdentity().getPid() == Process.myPid() && locationResult != null) {
1231                         deliverLocationResult = locationResult.deepCopy();
1232                     } else {
1233                         deliverLocationResult = locationResult;
1234                     }
1235 
1236                     // we currently don't hold a wakelock for getCurrentLocation deliveries
1237                     listener.deliverOnLocationChanged(deliverLocationResult, null);
1238                     EVENT_LOG.logProviderDeliveredLocations(mName,
1239                             locationResult != null ? locationResult.size() : 0, getIdentity());
1240                 }
1241 
1242                 @Override
1243                 public void onPostExecute(boolean success) {
1244                     // on failure we're automatically removed anyways, no need to attempt removal
1245                     // again
1246                     if (success) {
1247                         synchronized (mLock) {
1248                             remove();
1249                         }
1250                     }
1251                 }
1252             };
1253         }
1254 
1255         @Override
1256         public void onOperationFailure(ListenerOperation<LocationTransport> operation,
1257                 Exception e) {
1258             if (e instanceof RemoteException) {
1259                 Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
1260                 synchronized (mLock) {
1261                     remove();
1262                 }
1263             } else {
1264                 throw new AssertionError(e);
1265             }
1266         }
1267 
1268         @Override
1269         public void binderDied() {
1270             try {
1271                 if (D) {
1272                     Log.d(TAG, mName + " provider registration " + getIdentity() + " died");
1273                 }
1274 
1275                 synchronized (mLock) {
1276                     remove();
1277                 }
1278             } catch (RuntimeException e) {
1279                 // the caller may swallow runtime exceptions, so we rethrow as assertion errors to
1280                 // ensure the crash is seen
1281                 throw new AssertionError(e);
1282             }
1283         }
1284     }
1285 
1286     protected final Object mLock = new Object();
1287 
1288     protected final String mName;
1289     private final @Nullable PassiveLocationProviderManager mPassiveManager;
1290 
1291     protected final Context mContext;
1292 
1293     @GuardedBy("mLock")
1294     private @State int mState;
1295 
1296     // maps of user id to value
1297     @GuardedBy("mLock")
1298     private final SparseBooleanArray mEnabled; // null or not present means unknown
1299     @GuardedBy("mLock")
1300     private final SparseArray<LastLocation> mLastLocations;
1301 
1302     @GuardedBy("mLock")
1303     private final ArrayList<ProviderEnabledListener> mEnabledListeners;
1304 
1305     private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;
1306 
1307     protected final LocationManagerInternal mLocationManagerInternal;
1308     protected final LocationSettings mLocationSettings;
1309     protected final SettingsHelper mSettingsHelper;
1310     protected final UserInfoHelper mUserHelper;
1311     protected final AlarmHelper mAlarmHelper;
1312     protected final AppOpsHelper mAppOpsHelper;
1313     protected final LocationPermissionsHelper mLocationPermissionsHelper;
1314     protected final AppForegroundHelper mAppForegroundHelper;
1315     protected final LocationPowerSaveModeHelper mLocationPowerSaveModeHelper;
1316     protected final ScreenInteractiveHelper mScreenInteractiveHelper;
1317     protected final LocationAttributionHelper mLocationAttributionHelper;
1318     protected final LocationUsageLogger mLocationUsageLogger;
1319     protected final LocationFudger mLocationFudger;
1320 
1321     private final UserListener mUserChangedListener = this::onUserChanged;
1322     private final LocationSettings.LocationUserSettingsListener mLocationUserSettingsListener =
1323             this::onLocationUserSettingsChanged;
1324     private final UserSettingChangedListener mLocationEnabledChangedListener =
1325             this::onLocationEnabledChanged;
1326     private final GlobalSettingChangedListener mBackgroundThrottlePackageWhitelistChangedListener =
1327             this::onBackgroundThrottlePackageWhitelistChanged;
1328     private final UserSettingChangedListener mLocationPackageBlacklistChangedListener =
1329             this::onLocationPackageBlacklistChanged;
1330     private final LocationPermissionsListener mLocationPermissionsListener =
1331             new LocationPermissionsListener() {
1332                 @Override
1333                 public void onLocationPermissionsChanged(String packageName) {
1334                     LocationProviderManager.this.onLocationPermissionsChanged(packageName);
1335                 }
1336 
1337                 @Override
1338                 public void onLocationPermissionsChanged(int uid) {
1339                     LocationProviderManager.this.onLocationPermissionsChanged(uid);
1340                 }
1341             };
1342     private final AppForegroundListener mAppForegroundChangedListener =
1343             this::onAppForegroundChanged;
1344     private final GlobalSettingChangedListener mBackgroundThrottleIntervalChangedListener =
1345             this::onBackgroundThrottleIntervalChanged;
1346     private final GlobalSettingChangedListener mIgnoreSettingsPackageWhitelistChangedListener =
1347             this::onIgnoreSettingsWhitelistChanged;
1348     private final LocationPowerSaveModeChangedListener mLocationPowerSaveModeChangedListener =
1349             this::onLocationPowerSaveModeChanged;
1350     private final ScreenInteractiveChangedListener mScreenInteractiveChangedListener =
1351             this::onScreenInteractiveChanged;
1352 
1353     // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
1354     protected final MockableLocationProvider mProvider;
1355 
1356     @GuardedBy("mLock")
1357     private @Nullable OnAlarmListener mDelayedRegister;
1358 
1359     @GuardedBy("mLock")
1360     private @Nullable StateChangedListener mStateChangedListener;
1361 
1362     public LocationProviderManager(Context context, Injector injector,
1363             String name, @Nullable PassiveLocationProviderManager passiveManager) {
1364         mContext = context;
1365         mName = Objects.requireNonNull(name);
1366         mPassiveManager = passiveManager;
1367         mState = STATE_STOPPED;
1368         mEnabled = new SparseBooleanArray(2);
1369         mLastLocations = new SparseArray<>(2);
1370 
1371         mEnabledListeners = new ArrayList<>();
1372         mProviderRequestListeners = new CopyOnWriteArrayList<>();
1373 
1374         mLocationManagerInternal = Objects.requireNonNull(
1375                 LocalServices.getService(LocationManagerInternal.class));
1376         mLocationSettings = injector.getLocationSettings();
1377         mSettingsHelper = injector.getSettingsHelper();
1378         mUserHelper = injector.getUserInfoHelper();
1379         mAlarmHelper = injector.getAlarmHelper();
1380         mAppOpsHelper = injector.getAppOpsHelper();
1381         mLocationPermissionsHelper = injector.getLocationPermissionsHelper();
1382         mAppForegroundHelper = injector.getAppForegroundHelper();
1383         mLocationPowerSaveModeHelper = injector.getLocationPowerSaveModeHelper();
1384         mScreenInteractiveHelper = injector.getScreenInteractiveHelper();
1385         mLocationAttributionHelper = injector.getLocationAttributionHelper();
1386         mLocationUsageLogger = injector.getLocationUsageLogger();
1387         mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
1388 
1389         mProvider = new MockableLocationProvider(mLock);
1390 
1391         // set listener last, since this lets our reference escape
1392         mProvider.getController().setListener(this);
1393     }
1394 
1395     @Override
1396     public String getTag() {
1397         return TAG;
1398     }
1399 
1400     public void startManager(@Nullable StateChangedListener listener) {
1401         synchronized (mLock) {
1402             Preconditions.checkState(mState == STATE_STOPPED);
1403             mState = STATE_STARTED;
1404             mStateChangedListener = listener;
1405 
1406             mUserHelper.addListener(mUserChangedListener);
1407             mLocationSettings.registerLocationUserSettingsListener(mLocationUserSettingsListener);
1408             mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
1409 
1410             final long identity = Binder.clearCallingIdentity();
1411             try {
1412                 mProvider.getController().start();
1413                 onUserStarted(UserHandle.USER_ALL);
1414             } finally {
1415                 Binder.restoreCallingIdentity(identity);
1416             }
1417         }
1418     }
1419 
1420     public void stopManager() {
1421         synchronized (mLock) {
1422             Preconditions.checkState(mState == STATE_STARTED);
1423             mState = STATE_STOPPING;
1424 
1425             final long identity = Binder.clearCallingIdentity();
1426             try {
1427                 onEnabledChanged(UserHandle.USER_ALL);
1428                 removeRegistrationIf(key -> true);
1429                 mProvider.getController().stop();
1430             } finally {
1431                 Binder.restoreCallingIdentity(identity);
1432             }
1433 
1434             mUserHelper.removeListener(mUserChangedListener);
1435             mLocationSettings.unregisterLocationUserSettingsListener(mLocationUserSettingsListener);
1436             mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
1437 
1438             // if external entities are registering listeners it's their responsibility to
1439             // unregister them before stopManager() is called
1440             Preconditions.checkState(mEnabledListeners.isEmpty());
1441             mProviderRequestListeners.clear();
1442 
1443             mEnabled.clear();
1444             mLastLocations.clear();
1445             mStateChangedListener = null;
1446             mState = STATE_STOPPED;
1447         }
1448     }
1449 
1450     public String getName() {
1451         return mName;
1452     }
1453 
1454     public AbstractLocationProvider.State getState() {
1455         return mProvider.getState();
1456     }
1457 
1458     public @Nullable CallerIdentity getIdentity() {
1459         return mProvider.getState().identity;
1460     }
1461 
1462     public @Nullable ProviderProperties getProperties() {
1463         return mProvider.getState().properties;
1464     }
1465 
1466     public boolean hasProvider() {
1467         return mProvider.getProvider() != null;
1468     }
1469 
1470     public boolean isEnabled(int userId) {
1471         if (userId == UserHandle.USER_NULL) {
1472             return false;
1473         } else if (userId == UserHandle.USER_CURRENT) {
1474             return isEnabled(mUserHelper.getCurrentUserId());
1475         }
1476 
1477         Preconditions.checkArgument(userId >= 0);
1478 
1479         synchronized (mLock) {
1480             int index = mEnabled.indexOfKey(userId);
1481             if (index < 0) {
1482                 // this generally shouldn't occur, but might be possible due to race conditions
1483                 // on when we are notified of new users
1484                 Log.w(TAG, mName + " provider saw user " + userId + " unexpectedly");
1485                 onEnabledChanged(userId);
1486                 index = mEnabled.indexOfKey(userId);
1487             }
1488 
1489             return mEnabled.valueAt(index);
1490         }
1491     }
1492 
1493     public void addEnabledListener(ProviderEnabledListener listener) {
1494         synchronized (mLock) {
1495             Preconditions.checkState(mState != STATE_STOPPED);
1496             mEnabledListeners.add(listener);
1497         }
1498     }
1499 
1500     public void removeEnabledListener(ProviderEnabledListener listener) {
1501         synchronized (mLock) {
1502             Preconditions.checkState(mState != STATE_STOPPED);
1503             mEnabledListeners.remove(listener);
1504         }
1505     }
1506 
1507     /** Add a {@link IProviderRequestListener}. */
1508     public void addProviderRequestListener(IProviderRequestListener listener) {
1509         mProviderRequestListeners.add(listener);
1510     }
1511 
1512     /** Remove a {@link IProviderRequestListener}. */
1513     public void removeProviderRequestListener(IProviderRequestListener listener) {
1514         mProviderRequestListeners.remove(listener);
1515     }
1516 
1517     public void setRealProvider(@Nullable AbstractLocationProvider provider) {
1518         synchronized (mLock) {
1519             Preconditions.checkState(mState != STATE_STOPPED);
1520 
1521             final long identity = Binder.clearCallingIdentity();
1522             try {
1523                 mProvider.setRealProvider(provider);
1524             } finally {
1525                 Binder.restoreCallingIdentity(identity);
1526             }
1527         }
1528     }
1529 
1530     public void setMockProvider(@Nullable MockLocationProvider provider) {
1531         synchronized (mLock) {
1532             Preconditions.checkState(mState != STATE_STOPPED);
1533 
1534             EVENT_LOG.logProviderMocked(mName, provider != null);
1535 
1536             final long identity = Binder.clearCallingIdentity();
1537             try {
1538                 mProvider.setMockProvider(provider);
1539             } finally {
1540                 Binder.restoreCallingIdentity(identity);
1541             }
1542 
1543             // when removing a mock provider, also clear any mock last locations and reset the
1544             // location fudger. the mock provider could have been used to infer the current
1545             // location fudger offsets.
1546             if (provider == null) {
1547                 final int lastLocationSize = mLastLocations.size();
1548                 for (int i = 0; i < lastLocationSize; i++) {
1549                     mLastLocations.valueAt(i).clearMock();
1550                 }
1551 
1552                 mLocationFudger.resetOffsets();
1553             }
1554         }
1555     }
1556 
1557     public void setMockProviderAllowed(boolean enabled) {
1558         synchronized (mLock) {
1559             if (!mProvider.isMock()) {
1560                 throw new IllegalArgumentException(mName + " provider is not a test provider");
1561             }
1562 
1563             final long identity = Binder.clearCallingIdentity();
1564             try {
1565                 mProvider.setMockProviderAllowed(enabled);
1566             } finally {
1567                 Binder.restoreCallingIdentity(identity);
1568             }
1569         }
1570     }
1571 
1572     public void setMockProviderLocation(Location location) {
1573         synchronized (mLock) {
1574             if (!mProvider.isMock()) {
1575                 throw new IllegalArgumentException(mName + " provider is not a test provider");
1576             }
1577 
1578             String locationProvider = location.getProvider();
1579             if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
1580                 // The location has an explicit provider that is different from the mock
1581                 // provider name. The caller may be trying to fool us via b/33091107.
1582                 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
1583                         mName + "!=" + locationProvider);
1584             }
1585 
1586             final long identity = Binder.clearCallingIdentity();
1587             try {
1588                 mProvider.setMockProviderLocation(location);
1589             } finally {
1590                 Binder.restoreCallingIdentity(identity);
1591             }
1592         }
1593     }
1594 
1595     public @Nullable Location getLastLocation(LastLocationRequest request,
1596             CallerIdentity identity, @PermissionLevel int permissionLevel) {
1597         if (!isActive(request.isBypass(), identity)) {
1598             return null;
1599         }
1600 
1601         // lastly - note app ops
1602         if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
1603                 identity)) {
1604             return null;
1605         }
1606 
1607         Location location = getPermittedLocation(
1608                 getLastLocationUnsafe(
1609                         identity.getUserId(),
1610                         permissionLevel,
1611                         request.isBypass(),
1612                         Long.MAX_VALUE),
1613                 permissionLevel);
1614 
1615         if (location != null && identity.getPid() == Process.myPid()) {
1616             // if delivering to the same process, make a copy of the location first (since
1617             // location is mutable)
1618             location = new Location(location);
1619         }
1620 
1621         return location;
1622     }
1623 
1624     /**
1625      * This function does not perform any permissions or safety checks, by calling it you are
1626      * committing to performing all applicable checks yourself. This always returns a "fine"
1627      * location, even if the permissionLevel is coarse. You are responsible for coarsening the
1628      * location if necessary.
1629      */
1630     public @Nullable Location getLastLocationUnsafe(int userId,
1631             @PermissionLevel int permissionLevel, boolean isBypass,
1632             long maximumAgeMs) {
1633         if (userId == UserHandle.USER_ALL) {
1634             // find the most recent location across all users
1635             Location lastLocation = null;
1636             final int[] runningUserIds = mUserHelper.getRunningUserIds();
1637             for (int i = 0; i < runningUserIds.length; i++) {
1638                 Location next = getLastLocationUnsafe(runningUserIds[i], permissionLevel,
1639                         isBypass, maximumAgeMs);
1640                 if (lastLocation == null || (next != null && next.getElapsedRealtimeNanos()
1641                         > lastLocation.getElapsedRealtimeNanos())) {
1642                     lastLocation = next;
1643                 }
1644             }
1645             return lastLocation;
1646         } else if (userId == UserHandle.USER_CURRENT) {
1647             return getLastLocationUnsafe(mUserHelper.getCurrentUserId(), permissionLevel,
1648                     isBypass, maximumAgeMs);
1649         }
1650 
1651         Preconditions.checkArgument(userId >= 0);
1652 
1653         Location location;
1654         synchronized (mLock) {
1655             Preconditions.checkState(mState != STATE_STOPPED);
1656             LastLocation lastLocation = mLastLocations.get(userId);
1657             if (lastLocation == null) {
1658                 location = null;
1659             } else {
1660                 location = lastLocation.get(permissionLevel, isBypass);
1661             }
1662         }
1663 
1664         if (location == null) {
1665             return null;
1666         }
1667 
1668         if (location.getElapsedRealtimeAgeMillis() > maximumAgeMs) {
1669             return null;
1670         }
1671 
1672         return location;
1673     }
1674 
1675     public void injectLastLocation(Location location, int userId) {
1676         synchronized (mLock) {
1677             Preconditions.checkState(mState != STATE_STOPPED);
1678             if (getLastLocationUnsafe(userId, PERMISSION_FINE, false, Long.MAX_VALUE) == null) {
1679                 setLastLocation(location, userId);
1680             }
1681         }
1682     }
1683 
1684     private void setLastLocation(Location location, int userId) {
1685         if (userId == UserHandle.USER_ALL) {
1686             final int[] runningUserIds = mUserHelper.getRunningUserIds();
1687             for (int i = 0; i < runningUserIds.length; i++) {
1688                 setLastLocation(location, runningUserIds[i]);
1689             }
1690             return;
1691         } else if (userId == UserHandle.USER_CURRENT) {
1692             setLastLocation(location, mUserHelper.getCurrentUserId());
1693             return;
1694         }
1695 
1696         Preconditions.checkArgument(userId >= 0);
1697 
1698         synchronized (mLock) {
1699             LastLocation lastLocation = mLastLocations.get(userId);
1700             if (lastLocation == null) {
1701                 lastLocation = new LastLocation();
1702                 mLastLocations.put(userId, lastLocation);
1703             }
1704 
1705             if (isEnabled(userId)) {
1706                 lastLocation.set(location);
1707             }
1708             lastLocation.setBypass(location);
1709         }
1710     }
1711 
1712     public @Nullable ICancellationSignal getCurrentLocation(LocationRequest request,
1713             CallerIdentity identity, int permissionLevel, ILocationCallback callback) {
1714         if (request.getDurationMillis() > MAX_GET_CURRENT_LOCATION_TIMEOUT_MS) {
1715             request = new LocationRequest.Builder(request)
1716                     .setDurationMillis(MAX_GET_CURRENT_LOCATION_TIMEOUT_MS)
1717                     .build();
1718         }
1719 
1720         GetCurrentLocationListenerRegistration registration =
1721                 new GetCurrentLocationListenerRegistration(
1722                         request,
1723                         identity,
1724                         new GetCurrentLocationTransport(callback),
1725                         permissionLevel);
1726 
1727         synchronized (mLock) {
1728             Preconditions.checkState(mState != STATE_STOPPED);
1729             final long ident = Binder.clearCallingIdentity();
1730             try {
1731                 putRegistration(callback.asBinder(), registration);
1732                 if (!registration.isActive()) {
1733                     // if the registration never activated, fail it immediately
1734                     registration.deliverNull();
1735                 }
1736             } finally {
1737                 Binder.restoreCallingIdentity(ident);
1738             }
1739         }
1740 
1741         ICancellationSignal cancelTransport = CancellationSignal.createTransport();
1742         CancellationSignal.fromTransport(cancelTransport)
1743                 .setOnCancelListener(SingleUseCallback.wrap(
1744                         () -> {
1745                             synchronized (mLock) {
1746                                 removeRegistration(callback.asBinder(), registration);
1747                             }
1748                         }));
1749         return cancelTransport;
1750     }
1751 
1752     public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
1753         final long identity = Binder.clearCallingIdentity();
1754         try {
1755             mProvider.getController().sendExtraCommand(uid, pid, command, extras);
1756         } finally {
1757             Binder.restoreCallingIdentity(identity);
1758         }
1759     }
1760 
1761     public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
1762             @PermissionLevel int permissionLevel, ILocationListener listener) {
1763         LocationListenerRegistration registration = new LocationListenerRegistration(
1764                 request,
1765                 identity,
1766                 new LocationListenerTransport(listener),
1767                 permissionLevel);
1768 
1769         synchronized (mLock) {
1770             Preconditions.checkState(mState != STATE_STOPPED);
1771             final long ident = Binder.clearCallingIdentity();
1772             try {
1773                 putRegistration(listener.asBinder(), registration);
1774             } finally {
1775                 Binder.restoreCallingIdentity(ident);
1776             }
1777         }
1778     }
1779 
1780     public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
1781             @PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
1782         LocationPendingIntentRegistration registration = new LocationPendingIntentRegistration(
1783                 request,
1784                 callerIdentity,
1785                 new LocationPendingIntentTransport(mContext, pendingIntent),
1786                 permissionLevel);
1787 
1788         synchronized (mLock) {
1789             Preconditions.checkState(mState != STATE_STOPPED);
1790             final long identity = Binder.clearCallingIdentity();
1791             try {
1792                 putRegistration(pendingIntent, registration);
1793             } finally {
1794                 Binder.restoreCallingIdentity(identity);
1795             }
1796         }
1797     }
1798 
1799     public void flush(ILocationListener listener, int requestCode) {
1800         synchronized (mLock) {
1801             final long identity = Binder.clearCallingIdentity();
1802             try {
1803                 boolean flushed = updateRegistration(listener.asBinder(), registration -> {
1804                     registration.flush(requestCode);
1805                     return false;
1806                 });
1807                 if (!flushed) {
1808                     throw new IllegalArgumentException("unregistered listener cannot be flushed");
1809                 }
1810             } finally {
1811                 Binder.restoreCallingIdentity(identity);
1812             }
1813         }
1814     }
1815 
1816     public void flush(PendingIntent pendingIntent, int requestCode) {
1817         synchronized (mLock) {
1818             final long identity = Binder.clearCallingIdentity();
1819             try {
1820                 boolean flushed = updateRegistration(pendingIntent, registration -> {
1821                     registration.flush(requestCode);
1822                     return false;
1823                 });
1824                 if (!flushed) {
1825                     throw new IllegalArgumentException(
1826                             "unregistered pending intent cannot be flushed");
1827                 }
1828             } finally {
1829                 Binder.restoreCallingIdentity(identity);
1830             }
1831         }
1832     }
1833 
1834     public void unregisterLocationRequest(ILocationListener listener) {
1835         synchronized (mLock) {
1836             Preconditions.checkState(mState != STATE_STOPPED);
1837             final long identity = Binder.clearCallingIdentity();
1838             try {
1839                 removeRegistration(listener.asBinder());
1840             } finally {
1841                 Binder.restoreCallingIdentity(identity);
1842             }
1843         }
1844     }
1845 
1846     public void unregisterLocationRequest(PendingIntent pendingIntent) {
1847         synchronized (mLock) {
1848             Preconditions.checkState(mState != STATE_STOPPED);
1849             final long identity = Binder.clearCallingIdentity();
1850             try {
1851                 removeRegistration(pendingIntent);
1852             } finally {
1853                 Binder.restoreCallingIdentity(identity);
1854             }
1855         }
1856     }
1857 
1858     @GuardedBy("mLock")
1859     @Override
1860     protected void onRegister() {
1861         if (Build.IS_DEBUGGABLE) {
1862             Preconditions.checkState(Thread.holdsLock(mLock));
1863         }
1864 
1865         mSettingsHelper.addOnBackgroundThrottleIntervalChangedListener(
1866                 mBackgroundThrottleIntervalChangedListener);
1867         mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
1868                 mBackgroundThrottlePackageWhitelistChangedListener);
1869         mSettingsHelper.addOnLocationPackageBlacklistChangedListener(
1870                 mLocationPackageBlacklistChangedListener);
1871         mSettingsHelper.addIgnoreSettingsAllowlistChangedListener(
1872                 mIgnoreSettingsPackageWhitelistChangedListener);
1873         mLocationPermissionsHelper.addListener(mLocationPermissionsListener);
1874         mAppForegroundHelper.addListener(mAppForegroundChangedListener);
1875         mLocationPowerSaveModeHelper.addListener(mLocationPowerSaveModeChangedListener);
1876         mScreenInteractiveHelper.addListener(mScreenInteractiveChangedListener);
1877     }
1878 
1879     @GuardedBy("mLock")
1880     @Override
1881     protected void onUnregister() {
1882         if (Build.IS_DEBUGGABLE) {
1883             Preconditions.checkState(Thread.holdsLock(mLock));
1884         }
1885 
1886         mSettingsHelper.removeOnBackgroundThrottleIntervalChangedListener(
1887                 mBackgroundThrottleIntervalChangedListener);
1888         mSettingsHelper.removeOnBackgroundThrottlePackageWhitelistChangedListener(
1889                 mBackgroundThrottlePackageWhitelistChangedListener);
1890         mSettingsHelper.removeOnLocationPackageBlacklistChangedListener(
1891                 mLocationPackageBlacklistChangedListener);
1892         mSettingsHelper.removeIgnoreSettingsAllowlistChangedListener(
1893                 mIgnoreSettingsPackageWhitelistChangedListener);
1894         mLocationPermissionsHelper.removeListener(mLocationPermissionsListener);
1895         mAppForegroundHelper.removeListener(mAppForegroundChangedListener);
1896         mLocationPowerSaveModeHelper.removeListener(mLocationPowerSaveModeChangedListener);
1897         mScreenInteractiveHelper.removeListener(mScreenInteractiveChangedListener);
1898     }
1899 
1900     @GuardedBy("mLock")
1901     @Override
1902     protected void onRegistrationAdded(Object key, Registration registration) {
1903         if (Build.IS_DEBUGGABLE) {
1904             Preconditions.checkState(Thread.holdsLock(mLock));
1905         }
1906 
1907         mLocationUsageLogger.logLocationApiUsage(
1908                 LocationStatsEnums.USAGE_STARTED,
1909                 LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
1910                 registration.getIdentity().getPackageName(),
1911                 registration.getIdentity().getAttributionTag(),
1912                 mName,
1913                 registration.getRequest(),
1914                 key instanceof PendingIntent,
1915                 /* geofence= */ key instanceof IBinder,
1916                 null, registration.isForeground());
1917     }
1918 
1919     @GuardedBy("mLock")
1920     @Override
1921     protected void onRegistrationReplaced(Object key, Registration oldRegistration,
1922             Registration newRegistration) {
1923         // by saving the last delivered location state we are able to potentially delay the
1924         // resulting provider request longer and save additional power
1925         newRegistration.setLastDeliveredLocation(oldRegistration.getLastDeliveredLocation());
1926         super.onRegistrationReplaced(key, oldRegistration, newRegistration);
1927     }
1928 
1929     @GuardedBy("mLock")
1930     @Override
1931     protected void onRegistrationRemoved(Object key, Registration registration) {
1932         if (Build.IS_DEBUGGABLE) {
1933             Preconditions.checkState(Thread.holdsLock(mLock));
1934         }
1935 
1936         mLocationUsageLogger.logLocationApiUsage(
1937                 LocationStatsEnums.USAGE_ENDED,
1938                 LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
1939                 registration.getIdentity().getPackageName(),
1940                 registration.getIdentity().getAttributionTag(),
1941                 mName,
1942                 registration.getRequest(),
1943                 key instanceof PendingIntent,
1944                 /* geofence= */ key instanceof IBinder,
1945                 null, registration.isForeground());
1946     }
1947 
1948     @GuardedBy("mLock")
1949     @Override
1950     protected boolean registerWithService(ProviderRequest request,
1951             Collection<Registration> registrations) {
1952         return reregisterWithService(ProviderRequest.EMPTY_REQUEST, request, registrations);
1953     }
1954 
1955     @GuardedBy("mLock")
1956     @Override
1957     protected boolean reregisterWithService(ProviderRequest oldRequest,
1958             ProviderRequest newRequest, Collection<Registration> registrations) {
1959         if (Build.IS_DEBUGGABLE) {
1960             Preconditions.checkState(Thread.holdsLock(mLock));
1961         }
1962 
1963         if (mDelayedRegister != null) {
1964             mAlarmHelper.cancel(mDelayedRegister);
1965             mDelayedRegister = null;
1966         }
1967 
1968         // calculate how long the new request should be delayed before sending it off to the
1969         // provider, under the assumption that once we send the request off, the provider will
1970         // immediately attempt to deliver a new location satisfying that request.
1971         long delayMs;
1972         if (!oldRequest.isBypass() && newRequest.isBypass()) {
1973             delayMs = 0;
1974         } else if (newRequest.getIntervalMillis() > oldRequest.getIntervalMillis()) {
1975             // if the interval has increased, tell the provider immediately, so it can save power
1976             // (even though technically this could burn extra power in the short term by producing
1977             // an extra location - the provider itself is free to detect an increasing interval and
1978             // delay its own location)
1979             delayMs = 0;
1980         } else {
1981             delayMs = calculateRequestDelayMillis(newRequest.getIntervalMillis(), registrations);
1982         }
1983 
1984         // the delay should never exceed the new interval
1985         Preconditions.checkState(delayMs >= 0 && delayMs <= newRequest.getIntervalMillis());
1986 
1987         if (delayMs < MIN_REQUEST_DELAY_MS) {
1988             setProviderRequest(newRequest);
1989         } else {
1990             if (D) {
1991                 Log.d(TAG, mName + " provider delaying request update " + newRequest + " by "
1992                         + TimeUtils.formatDuration(delayMs));
1993             }
1994 
1995             mDelayedRegister = new OnAlarmListener() {
1996                 @Override
1997                 public void onAlarm() {
1998                     synchronized (mLock) {
1999                         if (mDelayedRegister == this) {
2000                             setProviderRequest(newRequest);
2001                             mDelayedRegister = null;
2002                         }
2003                     }
2004                 }
2005             };
2006             // Set WorkSource to null in order to ensure the alarm wakes up the device even when it
2007             // is idle. Do this when the cost of waking up the device is less than the power cost of
2008             // not performing the actions set off by the alarm, such as unregistering a location
2009             // request.
2010             mAlarmHelper.setDelayedAlarm(delayMs, mDelayedRegister, null);
2011         }
2012 
2013         return true;
2014     }
2015 
2016     @GuardedBy("mLock")
2017     @Override
2018     protected void unregisterWithService() {
2019         if (Build.IS_DEBUGGABLE) {
2020             Preconditions.checkState(Thread.holdsLock(mLock));
2021         }
2022 
2023         setProviderRequest(ProviderRequest.EMPTY_REQUEST);
2024     }
2025 
2026     @GuardedBy("mLock")
2027     void setProviderRequest(ProviderRequest request) {
2028         EVENT_LOG.logProviderUpdateRequest(mName, request);
2029         mProvider.getController().setRequest(request);
2030 
2031         FgThread.getHandler().post(() -> {
2032             for (IProviderRequestListener listener : mProviderRequestListeners) {
2033                 try {
2034                     listener.onProviderRequestChanged(mName, request);
2035                 } catch (RemoteException e) {
2036                     mProviderRequestListeners.remove(listener);
2037                 }
2038             }
2039         });
2040     }
2041 
2042     @GuardedBy("mLock")
2043     @Override
2044     protected boolean isActive(Registration registration) {
2045         if (Build.IS_DEBUGGABLE) {
2046             Preconditions.checkState(Thread.holdsLock(mLock));
2047         }
2048 
2049         if (!registration.isPermitted()) {
2050             return false;
2051         }
2052 
2053         boolean isBypass = registration.getRequest().isBypass();
2054         if (!isActive(isBypass, registration.getIdentity())) {
2055             return false;
2056         }
2057 
2058         if (!isBypass) {
2059             switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
2060                 case LOCATION_MODE_FOREGROUND_ONLY:
2061                     if (!registration.isForeground()) {
2062                         return false;
2063                     }
2064                     break;
2065                 case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
2066                     if (!GPS_PROVIDER.equals(mName)) {
2067                         break;
2068                     }
2069                     // fall through
2070                 case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF:
2071                     // fall through
2072                 case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
2073                     if (!mScreenInteractiveHelper.isInteractive()) {
2074                         return false;
2075                     }
2076                     break;
2077                 case LOCATION_MODE_NO_CHANGE:
2078                     // fall through
2079                 default:
2080                     break;
2081             }
2082         }
2083 
2084         return true;
2085     }
2086 
2087     private boolean isActive(boolean isBypass, CallerIdentity identity) {
2088         if (identity.isSystemServer()) {
2089             if (!isBypass) {
2090                 if (!isEnabled(mUserHelper.getCurrentUserId())) {
2091                     return false;
2092                 }
2093             }
2094         } else {
2095             if (!isBypass) {
2096                 if (!isEnabled(identity.getUserId())) {
2097                     return false;
2098                 }
2099                 if (!mUserHelper.isCurrentUserId(identity.getUserId())) {
2100                     return false;
2101                 }
2102             }
2103             if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
2104                     identity.getPackageName())) {
2105                 return false;
2106             }
2107         }
2108 
2109         return true;
2110     }
2111 
2112     @GuardedBy("mLock")
2113     @Override
2114     protected ProviderRequest mergeRegistrations(Collection<Registration> registrations) {
2115         if (Build.IS_DEBUGGABLE) {
2116             Preconditions.checkState(Thread.holdsLock(mLock));
2117         }
2118 
2119         long intervalMs = ProviderRequest.INTERVAL_DISABLED;
2120         int quality = LocationRequest.QUALITY_LOW_POWER;
2121         long maxUpdateDelayMs = Long.MAX_VALUE;
2122         boolean adasGnssBypass = false;
2123         boolean locationSettingsIgnored = false;
2124         boolean lowPower = true;
2125 
2126         for (Registration registration : registrations) {
2127             LocationRequest request = registration.getRequest();
2128 
2129             // passive requests do not contribute to the provider request, and passive requests
2130             // must handle the batching parameters of non-passive requests
2131             if (request.getIntervalMillis() == LocationRequest.PASSIVE_INTERVAL) {
2132                 continue;
2133             }
2134 
2135             intervalMs = min(request.getIntervalMillis(), intervalMs);
2136             quality = min(request.getQuality(), quality);
2137             maxUpdateDelayMs = min(request.getMaxUpdateDelayMillis(), maxUpdateDelayMs);
2138             adasGnssBypass |= request.isAdasGnssBypass();
2139             locationSettingsIgnored |= request.isLocationSettingsIgnored();
2140             lowPower &= request.isLowPower();
2141         }
2142 
2143         if (intervalMs == ProviderRequest.INTERVAL_DISABLED) {
2144             return ProviderRequest.EMPTY_REQUEST;
2145         }
2146 
2147         if (maxUpdateDelayMs / 2 < intervalMs) {
2148             // reduces churn if only the batching parameter has changed
2149             maxUpdateDelayMs = 0;
2150         }
2151 
2152         // calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
2153         // interval slightly higher that the minimum interval, and spread the blame across all
2154         // contributing registrations under that threshold (since worksource does not allow us to
2155         // represent differing power blame ratios).
2156         long thresholdIntervalMs;
2157         try {
2158             thresholdIntervalMs = Math.multiplyExact(Math.addExact(intervalMs, 1000) / 2, 3);
2159         } catch (ArithmeticException e) {
2160             // check for and handle overflow by setting to one below the passive interval so passive
2161             // requests are automatically skipped
2162             thresholdIntervalMs = LocationRequest.PASSIVE_INTERVAL - 1;
2163         }
2164 
2165         WorkSource workSource = new WorkSource();
2166         for (Registration registration : registrations) {
2167             if (registration.getRequest().getIntervalMillis() <= thresholdIntervalMs) {
2168                 workSource.add(registration.getRequest().getWorkSource());
2169             }
2170         }
2171 
2172         return new ProviderRequest.Builder()
2173                 .setIntervalMillis(intervalMs)
2174                 .setQuality(quality)
2175                 .setMaxUpdateDelayMillis(maxUpdateDelayMs)
2176                 .setAdasGnssBypass(adasGnssBypass)
2177                 .setLocationSettingsIgnored(locationSettingsIgnored)
2178                 .setLowPower(lowPower)
2179                 .setWorkSource(workSource)
2180                 .build();
2181     }
2182 
2183     @GuardedBy("mLock")
2184     protected long calculateRequestDelayMillis(long newIntervalMs,
2185             Collection<Registration> registrations) {
2186         // calculate the minimum delay across all registrations, ensuring that it is not more than
2187         // the requested interval
2188         long delayMs = newIntervalMs;
2189         for (Registration registration : registrations) {
2190             if (delayMs == 0) {
2191                 break;
2192             }
2193 
2194             LocationRequest locationRequest = registration.getRequest();
2195             Location last = registration.getLastDeliveredLocation();
2196 
2197             if (last == null && !locationRequest.isLocationSettingsIgnored()) {
2198                 // if this request has never gotten any location and it's not ignoring location
2199                 // settings, then we pretend that this request has gotten the last applicable cached
2200                 // location for our calculations instead. this prevents spammy add/remove behavior
2201                 last = getLastLocationUnsafe(
2202                         registration.getIdentity().getUserId(),
2203                         registration.getPermissionLevel(),
2204                         false,
2205                         locationRequest.getIntervalMillis());
2206             }
2207 
2208             long registrationDelayMs;
2209             if (last == null) {
2210                 // if this request has never gotten any location then there's no delay
2211                 registrationDelayMs = 0;
2212             } else {
2213                 // otherwise the delay is the amount of time until the next location is expected
2214                 registrationDelayMs = max(0,
2215                         locationRequest.getIntervalMillis() - last.getElapsedRealtimeAgeMillis());
2216             }
2217 
2218             delayMs = min(delayMs, registrationDelayMs);
2219         }
2220 
2221         return delayMs;
2222     }
2223 
2224     private void onUserChanged(int userId, int change) {
2225         synchronized (mLock) {
2226             if (mState == STATE_STOPPED) {
2227                 return;
2228             }
2229 
2230             switch (change) {
2231                 case UserListener.CURRENT_USER_CHANGED:
2232                     updateRegistrations(
2233                             registration -> registration.getIdentity().getUserId() == userId);
2234                     break;
2235                 case UserListener.USER_STARTED:
2236                     onUserStarted(userId);
2237                     break;
2238                 case UserListener.USER_STOPPED:
2239                     onUserStopped(userId);
2240                     break;
2241             }
2242         }
2243     }
2244 
2245     private void onLocationUserSettingsChanged(int userId, LocationUserSettings oldSettings,
2246             LocationUserSettings newSettings) {
2247         if (oldSettings.isAdasGnssLocationEnabled() != newSettings.isAdasGnssLocationEnabled()) {
2248             synchronized (mLock) {
2249                 updateRegistrations(
2250                         registration -> registration.onAdasGnssLocationEnabledChanged(userId));
2251             }
2252         }
2253     }
2254 
2255     private void onLocationEnabledChanged(int userId) {
2256         synchronized (mLock) {
2257             if (mState == STATE_STOPPED) {
2258                 return;
2259             }
2260 
2261             onEnabledChanged(userId);
2262         }
2263     }
2264 
2265     private void onScreenInteractiveChanged(boolean screenInteractive) {
2266         synchronized (mLock) {
2267             switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
2268                 case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
2269                     if (!GPS_PROVIDER.equals(mName)) {
2270                         break;
2271                     }
2272                     // fall through
2273                 case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF:
2274                     // fall through
2275                 case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
2276                     updateRegistrations(registration -> true);
2277                     break;
2278                 default:
2279                     break;
2280             }
2281         }
2282     }
2283 
2284     private void onBackgroundThrottlePackageWhitelistChanged() {
2285         synchronized (mLock) {
2286             updateRegistrations(Registration::onProviderLocationRequestChanged);
2287         }
2288     }
2289 
2290     private void onBackgroundThrottleIntervalChanged() {
2291         synchronized (mLock) {
2292             updateRegistrations(Registration::onProviderLocationRequestChanged);
2293         }
2294     }
2295 
2296     private void onLocationPowerSaveModeChanged(@LocationPowerSaveMode int locationPowerSaveMode) {
2297         synchronized (mLock) {
2298             // this is rare, just assume everything has changed to keep it simple
2299             updateRegistrations(registration -> true);
2300         }
2301     }
2302 
2303     private void onAppForegroundChanged(int uid, boolean foreground) {
2304         synchronized (mLock) {
2305             updateRegistrations(registration -> registration.onForegroundChanged(uid, foreground));
2306         }
2307     }
2308 
2309     private void onIgnoreSettingsWhitelistChanged() {
2310         synchronized (mLock) {
2311             updateRegistrations(Registration::onProviderLocationRequestChanged);
2312         }
2313     }
2314 
2315     private void onLocationPackageBlacklistChanged(int userId) {
2316         synchronized (mLock) {
2317             updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
2318         }
2319     }
2320 
2321     private void onLocationPermissionsChanged(String packageName) {
2322         synchronized (mLock) {
2323             updateRegistrations(
2324                     registration -> registration.onLocationPermissionsChanged(packageName));
2325         }
2326     }
2327 
2328     private void onLocationPermissionsChanged(int uid) {
2329         synchronized (mLock) {
2330             updateRegistrations(registration -> registration.onLocationPermissionsChanged(uid));
2331         }
2332     }
2333 
2334     @GuardedBy("mLock")
2335     @Override
2336     public void onStateChanged(
2337             AbstractLocationProvider.State oldState, AbstractLocationProvider.State newState) {
2338         if (Build.IS_DEBUGGABLE) {
2339             Preconditions.checkState(Thread.holdsLock(mLock));
2340         }
2341 
2342         if (oldState.allowed != newState.allowed) {
2343             onEnabledChanged(UserHandle.USER_ALL);
2344         }
2345 
2346         if (!Objects.equals(oldState.properties, newState.properties)) {
2347             updateRegistrations(Registration::onProviderPropertiesChanged);
2348         }
2349 
2350         if (mStateChangedListener != null) {
2351             StateChangedListener listener = mStateChangedListener;
2352             FgThread.getExecutor().execute(
2353                     () -> listener.onStateChanged(mName, oldState, newState));
2354         }
2355     }
2356 
2357     @GuardedBy("mLock")
2358     @Override
2359     public void onReportLocation(LocationResult locationResult) {
2360         if (Build.IS_DEBUGGABLE) {
2361             Preconditions.checkState(Thread.holdsLock(mLock));
2362         }
2363 
2364         LocationResult filtered;
2365         if (mPassiveManager != null) {
2366             filtered = locationResult.filter(location -> {
2367                 if (!location.isMock()) {
2368                     if (location.getLatitude() == 0 && location.getLongitude() == 0) {
2369                         Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
2370                         return false;
2371                     }
2372                 }
2373 
2374                 if (!location.isComplete()) {
2375                     Log.w(TAG, "blocking incomplete location from " + mName + " provider");
2376                     return false;
2377                 }
2378 
2379                 return true;
2380             });
2381 
2382             if (filtered == null) {
2383                 return;
2384             }
2385 
2386             // don't log location received for passive provider because it's spammy
2387             EVENT_LOG.logProviderReceivedLocations(mName, filtered.size());
2388         } else {
2389             // passive provider should get already filtered results as input
2390             filtered = locationResult;
2391         }
2392 
2393         // update last location
2394         setLastLocation(filtered.getLastLocation(), UserHandle.USER_ALL);
2395 
2396         // attempt listener delivery
2397         deliverToListeners(registration -> {
2398             return registration.acceptLocationChange(filtered);
2399         });
2400 
2401         // notify passive provider
2402         if (mPassiveManager != null) {
2403             mPassiveManager.updateLocation(filtered);
2404         }
2405     }
2406 
2407     @GuardedBy("mLock")
2408     private void onUserStarted(int userId) {
2409         if (Build.IS_DEBUGGABLE) {
2410             Preconditions.checkState(Thread.holdsLock(mLock));
2411         }
2412 
2413         if (userId == UserHandle.USER_NULL) {
2414             return;
2415         }
2416 
2417         if (userId == UserHandle.USER_ALL) {
2418             // clear the user's prior enabled state to prevent broadcast of enabled state change
2419             mEnabled.clear();
2420             onEnabledChanged(UserHandle.USER_ALL);
2421         } else {
2422             Preconditions.checkArgument(userId >= 0);
2423 
2424             // clear the user's prior enabled state to prevent broadcast of enabled state change
2425             mEnabled.delete(userId);
2426             onEnabledChanged(userId);
2427         }
2428     }
2429 
2430     @GuardedBy("mLock")
2431     private void onUserStopped(int userId) {
2432         if (Build.IS_DEBUGGABLE) {
2433             Preconditions.checkState(Thread.holdsLock(mLock));
2434         }
2435 
2436         if (userId == UserHandle.USER_NULL) {
2437             return;
2438         }
2439 
2440         if (userId == UserHandle.USER_ALL) {
2441             mEnabled.clear();
2442             mLastLocations.clear();
2443         } else {
2444             Preconditions.checkArgument(userId >= 0);
2445             mEnabled.delete(userId);
2446             mLastLocations.remove(userId);
2447         }
2448     }
2449 
2450     @GuardedBy("mLock")
2451     private void onEnabledChanged(int userId) {
2452         if (Build.IS_DEBUGGABLE) {
2453             Preconditions.checkState(Thread.holdsLock(mLock));
2454         }
2455 
2456         if (userId == UserHandle.USER_NULL) {
2457             // used during initialization - ignore since many lower level operations (checking
2458             // settings for instance) do not support the null user
2459             return;
2460         } else if (userId == UserHandle.USER_ALL) {
2461             final int[] runningUserIds = mUserHelper.getRunningUserIds();
2462             for (int i = 0; i < runningUserIds.length; i++) {
2463                 onEnabledChanged(runningUserIds[i]);
2464             }
2465             return;
2466         }
2467 
2468         Preconditions.checkArgument(userId >= 0);
2469 
2470         boolean enabled = mState == STATE_STARTED
2471                 && mProvider.getState().allowed
2472                 && mSettingsHelper.isLocationEnabled(userId);
2473 
2474         int index = mEnabled.indexOfKey(userId);
2475         Boolean wasEnabled = index < 0 ? null : mEnabled.valueAt(index);
2476         if (wasEnabled != null && wasEnabled == enabled) {
2477             return;
2478         }
2479 
2480         mEnabled.put(userId, enabled);
2481 
2482         // don't log unknown -> false transitions for brevity
2483         if (wasEnabled != null || enabled) {
2484             if (D) {
2485                 Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
2486             }
2487             EVENT_LOG.logProviderEnabled(mName, userId, enabled);
2488         }
2489 
2490         // clear last locations if we become disabled
2491         if (!enabled) {
2492             LastLocation lastLocation = mLastLocations.get(userId);
2493             if (lastLocation != null) {
2494                 lastLocation.clearLocations();
2495             }
2496         }
2497 
2498         // do not send change notifications if we just saw this user for the first time
2499         if (wasEnabled != null) {
2500             // passive provider never get public updates for legacy reasons
2501             if (!PASSIVE_PROVIDER.equals(mName)) {
2502                 Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)
2503                         .putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName)
2504                         .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, enabled)
2505                         .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
2506                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
2507                 mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
2508             }
2509 
2510             // send updates to internal listeners - since we expect listener changes to be more
2511             // frequent than enabled changes, we use copy-on-read instead of copy-on-write
2512             if (!mEnabledListeners.isEmpty()) {
2513                 ProviderEnabledListener[] listeners = mEnabledListeners.toArray(
2514                         new ProviderEnabledListener[0]);
2515                 FgThread.getHandler().post(() -> {
2516                     for (int i = 0; i < listeners.length; i++) {
2517                         listeners[i].onProviderEnabledChanged(mName, userId, enabled);
2518                     }
2519                 });
2520             }
2521         }
2522 
2523         // update active state of affected registrations
2524         updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
2525     }
2526 
2527     @Nullable Location getPermittedLocation(@Nullable Location fineLocation,
2528             @PermissionLevel int permissionLevel) {
2529         switch (permissionLevel) {
2530             case PERMISSION_FINE:
2531                 return fineLocation;
2532             case PERMISSION_COARSE:
2533                 return fineLocation != null ? mLocationFudger.createCoarse(fineLocation) : null;
2534             default:
2535                 // shouldn't be possible to have a client added without location permissions
2536                 throw new AssertionError();
2537         }
2538     }
2539 
2540     @Nullable LocationResult getPermittedLocationResult(
2541             @Nullable LocationResult fineLocationResult, @PermissionLevel int permissionLevel) {
2542         switch (permissionLevel) {
2543             case PERMISSION_FINE:
2544                 return fineLocationResult;
2545             case PERMISSION_COARSE:
2546                 return fineLocationResult != null ? mLocationFudger.createCoarse(fineLocationResult)
2547                         : null;
2548             default:
2549                 // shouldn't be possible to have a client added without location permissions
2550                 throw new AssertionError();
2551         }
2552     }
2553 
2554     public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
2555         synchronized (mLock) {
2556             ipw.print(mName);
2557             ipw.print(" provider");
2558             if (mProvider.isMock()) {
2559                 ipw.print(" [mock]");
2560             }
2561             ipw.println(":");
2562             ipw.increaseIndent();
2563 
2564             super.dump(fd, ipw, args);
2565 
2566             int[] userIds = mUserHelper.getRunningUserIds();
2567             for (int userId : userIds) {
2568                 if (userIds.length != 1) {
2569                     ipw.print("user ");
2570                     ipw.print(userId);
2571                     ipw.println(":");
2572                     ipw.increaseIndent();
2573                 }
2574                 ipw.print("last location=");
2575                 ipw.println(getLastLocationUnsafe(userId, PERMISSION_FINE, false, Long.MAX_VALUE));
2576                 ipw.print("enabled=");
2577                 ipw.println(isEnabled(userId));
2578                 if (userIds.length != 1) {
2579                     ipw.decreaseIndent();
2580                 }
2581             }
2582         }
2583 
2584         mProvider.dump(fd, ipw, args);
2585 
2586         ipw.decreaseIndent();
2587     }
2588 
2589     @Override
2590     protected String getServiceState() {
2591         return mProvider.getCurrentRequest().toString();
2592     }
2593 
2594     private static class LastLocation {
2595 
2596         private @Nullable Location mFineLocation;
2597         private @Nullable Location mCoarseLocation;
2598         private @Nullable Location mFineBypassLocation;
2599         private @Nullable Location mCoarseBypassLocation;
2600 
2601         LastLocation() {}
2602 
2603         public void clearMock() {
2604             if (mFineLocation != null && mFineLocation.isMock()) {
2605                 mFineLocation = null;
2606             }
2607             if (mCoarseLocation != null && mCoarseLocation.isMock()) {
2608                 mCoarseLocation = null;
2609             }
2610             if (mFineBypassLocation != null && mFineBypassLocation.isMock()) {
2611                 mFineBypassLocation = null;
2612             }
2613             if (mCoarseBypassLocation != null && mCoarseBypassLocation.isMock()) {
2614                 mCoarseBypassLocation = null;
2615             }
2616         }
2617 
2618         public void clearLocations() {
2619             mFineLocation = null;
2620             mCoarseLocation = null;
2621         }
2622 
2623         public @Nullable Location get(@PermissionLevel int permissionLevel,
2624                 boolean isBypass) {
2625             switch (permissionLevel) {
2626                 case PERMISSION_FINE:
2627                     if (isBypass) {
2628                         return mFineBypassLocation;
2629                     } else {
2630                         return mFineLocation;
2631                     }
2632                 case PERMISSION_COARSE:
2633                     if (isBypass) {
2634                         return mCoarseBypassLocation;
2635                     } else {
2636                         return mCoarseLocation;
2637                     }
2638                 default:
2639                     // shouldn't be possible to have a client added without location permissions
2640                     throw new AssertionError();
2641             }
2642         }
2643 
2644         public void set(Location location) {
2645             mFineLocation = calculateNextFine(mFineLocation, location);
2646             mCoarseLocation = calculateNextCoarse(mCoarseLocation, location);
2647         }
2648 
2649         public void setBypass(Location location) {
2650             mFineBypassLocation = calculateNextFine(mFineBypassLocation, location);
2651             mCoarseBypassLocation = calculateNextCoarse(mCoarseBypassLocation, location);
2652         }
2653 
2654         private Location calculateNextFine(@Nullable Location oldFine, Location newFine) {
2655             if (oldFine == null) {
2656                 return newFine;
2657             }
2658 
2659             // update last fine interval only if more recent
2660             if (newFine.getElapsedRealtimeNanos() > oldFine.getElapsedRealtimeNanos()) {
2661                 return newFine;
2662             } else {
2663                 return oldFine;
2664             }
2665         }
2666 
2667         private Location calculateNextCoarse(@Nullable Location oldCoarse, Location newCoarse) {
2668             if (oldCoarse == null) {
2669                 return newCoarse;
2670             }
2671 
2672             // update last coarse interval only if enough time has passed
2673             if (newCoarse.getElapsedRealtimeMillis() - MIN_COARSE_INTERVAL_MS
2674                     > oldCoarse.getElapsedRealtimeMillis()) {
2675                 return newCoarse;
2676             } else {
2677                 return oldCoarse;
2678             }
2679         }
2680     }
2681 
2682     private static class SingleUseCallback extends IRemoteCallback.Stub implements Runnable,
2683             CancellationSignal.OnCancelListener {
2684 
2685         public static @Nullable SingleUseCallback wrap(@Nullable Runnable callback) {
2686             return callback == null ? null : new SingleUseCallback(callback);
2687         }
2688 
2689         @GuardedBy("this")
2690         private @Nullable Runnable mCallback;
2691 
2692         private SingleUseCallback(Runnable callback) {
2693             mCallback = Objects.requireNonNull(callback);
2694         }
2695 
2696         @Override
2697         public void sendResult(Bundle data) {
2698             run();
2699         }
2700 
2701         @Override
2702         public void onCancel() {
2703             run();
2704         }
2705 
2706         @Override
2707         public void run() {
2708             Runnable callback;
2709             synchronized (this) {
2710                 callback = mCallback;
2711                 mCallback = null;
2712             }
2713 
2714             // prevent this callback from being run more than once - otherwise this could provide an
2715             // attack vector for a malicious app to break assumptions on how many times a callback
2716             // may be invoked, and thus crash system server.
2717             if (callback == null) {
2718                 return;
2719             }
2720 
2721             final long identity = Binder.clearCallingIdentity();
2722             try {
2723                 callback.run();
2724             } catch (RuntimeException e) {
2725                 // since this is within a oneway binder transaction there is nowhere
2726                 // for exceptions to go - move onto another thread to crash system
2727                 // server so we find out about it
2728                 FgThread.getExecutor().execute(() -> {
2729                     throw new AssertionError(e);
2730                 });
2731                 throw e;
2732             } finally {
2733                 Binder.restoreCallingIdentity(identity);
2734             }
2735         }
2736     }
2737 }
2738