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