LocationManagerService.java revision bb608c8958a96b450094417482ba05126ce0c8f0
1/*
2 * Copyright (C) 2007 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
17package com.android.server;
18
19import android.app.ActivityManager;
20import android.annotation.NonNull;
21import android.content.pm.PackageManagerInternal;
22import android.util.ArrayMap;
23import android.util.ArraySet;
24import com.android.internal.content.PackageMonitor;
25import com.android.internal.location.ProviderProperties;
26import com.android.internal.location.ProviderRequest;
27import com.android.internal.os.BackgroundThread;
28import com.android.internal.util.ArrayUtils;
29import com.android.internal.util.DumpUtils;
30import com.android.server.location.ActivityRecognitionProxy;
31import com.android.server.location.FlpHardwareProvider;
32import com.android.server.location.FusedProxy;
33import com.android.server.location.GeocoderProxy;
34import com.android.server.location.GeofenceManager;
35import com.android.server.location.GeofenceProxy;
36import com.android.server.location.GnssLocationProvider;
37import com.android.server.location.GnssMeasurementsProvider;
38import com.android.server.location.GnssNavigationMessageProvider;
39import com.android.server.location.LocationBlacklist;
40import com.android.server.location.LocationFudger;
41import com.android.server.location.LocationProviderInterface;
42import com.android.server.location.LocationProviderProxy;
43import com.android.server.location.LocationRequestStatistics;
44import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
45import com.android.server.location.LocationRequestStatistics.PackageStatistics;
46import com.android.server.location.MockProvider;
47import com.android.server.location.PassiveProvider;
48
49import android.app.AppOpsManager;
50import android.app.PendingIntent;
51import android.content.BroadcastReceiver;
52import android.content.ContentResolver;
53import android.content.Context;
54import android.content.Intent;
55import android.content.IntentFilter;
56import android.content.pm.ApplicationInfo;
57import android.content.pm.PackageInfo;
58import android.content.pm.PackageManager;
59import android.content.pm.PackageManager.NameNotFoundException;
60import android.content.pm.ResolveInfo;
61import android.content.pm.Signature;
62import android.content.res.Resources;
63import android.database.ContentObserver;
64import android.hardware.location.ActivityRecognitionHardware;
65import android.location.Address;
66import android.location.Criteria;
67import android.location.GeocoderParams;
68import android.location.Geofence;
69import android.location.IBatchedLocationCallback;
70import android.location.IGnssMeasurementsListener;
71import android.location.IGnssStatusListener;
72import android.location.IGnssStatusProvider;
73import android.location.IGpsGeofenceHardware;
74import android.location.IGnssNavigationMessageListener;
75import android.location.ILocationListener;
76import android.location.ILocationManager;
77import android.location.INetInitiatedListener;
78import android.location.Location;
79import android.location.LocationManager;
80import android.location.LocationProvider;
81import android.location.LocationRequest;
82import android.os.Binder;
83import android.os.Bundle;
84import android.os.Handler;
85import android.os.IBinder;
86import android.os.Looper;
87import android.os.Message;
88import android.os.PowerManager;
89import android.os.Process;
90import android.os.RemoteException;
91import android.os.SystemClock;
92import android.os.UserHandle;
93import android.os.UserManager;
94import android.os.WorkSource;
95import android.provider.Settings;
96import android.text.TextUtils;
97import android.util.EventLog;
98import android.util.Log;
99import android.util.Slog;
100
101import java.io.FileDescriptor;
102import java.io.PrintWriter;
103import java.util.ArrayList;
104import java.util.Arrays;
105import java.util.HashMap;
106import java.util.HashSet;
107import java.util.List;
108import java.util.Map;
109import java.util.Map.Entry;
110import java.util.NoSuchElementException;
111import java.util.Set;
112
113/**
114 * The service class that manages LocationProviders and issues location
115 * updates and alerts.
116 */
117public class LocationManagerService extends ILocationManager.Stub {
118    private static final String TAG = "LocationManagerService";
119    public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
120
121    private static final String WAKELOCK_KEY = TAG;
122
123    // Location resolution level: no location data whatsoever
124    private static final int RESOLUTION_LEVEL_NONE = 0;
125    // Location resolution level: coarse location data only
126    private static final int RESOLUTION_LEVEL_COARSE = 1;
127    // Location resolution level: fine location data
128    private static final int RESOLUTION_LEVEL_FINE = 2;
129
130    private static final String ACCESS_MOCK_LOCATION =
131            android.Manifest.permission.ACCESS_MOCK_LOCATION;
132    private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
133            android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
134    private static final String INSTALL_LOCATION_PROVIDER =
135            android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
136
137    private static final String NETWORK_LOCATION_SERVICE_ACTION =
138            "com.android.location.service.v3.NetworkLocationProvider";
139    private static final String FUSED_LOCATION_SERVICE_ACTION =
140            "com.android.location.service.FusedLocationProvider";
141
142    private static final int MSG_LOCATION_CHANGED = 1;
143
144    private static final long NANOS_PER_MILLI = 1000000L;
145
146    // The maximum interval a location request can have and still be considered "high power".
147    private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
148
149    // default background throttling interval if not overriden in settings
150    private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
151
152    // Location Providers may sometimes deliver location updates
153    // slightly faster that requested - provide grace period so
154    // we don't unnecessarily filter events that are otherwise on
155    // time
156    private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
157
158    private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
159
160    private final Context mContext;
161    private final AppOpsManager mAppOps;
162
163    // used internally for synchronization
164    private final Object mLock = new Object();
165
166    // --- fields below are final after systemRunning() ---
167    private LocationFudger mLocationFudger;
168    private GeofenceManager mGeofenceManager;
169    private PackageManager mPackageManager;
170    private PowerManager mPowerManager;
171    private ActivityManager mActivityManager;
172    private UserManager mUserManager;
173    private GeocoderProxy mGeocodeProvider;
174    private IGnssStatusProvider mGnssStatusProvider;
175    private INetInitiatedListener mNetInitiatedListener;
176    private LocationWorkerHandler mLocationHandler;
177    private PassiveProvider mPassiveProvider;  // track passive provider for special cases
178    private LocationBlacklist mBlacklist;
179    private GnssMeasurementsProvider mGnssMeasurementsProvider;
180    private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
181    private IGpsGeofenceHardware mGpsGeofenceProxy;
182
183    // --- fields below are protected by mLock ---
184    // Set of providers that are explicitly enabled
185    // Only used by passive, fused & test.  Network & GPS are controlled separately, and not listed.
186    private final Set<String> mEnabledProviders = new HashSet<>();
187
188    // Set of providers that are explicitly disabled
189    private final Set<String> mDisabledProviders = new HashSet<>();
190
191    // Mock (test) providers
192    private final HashMap<String, MockProvider> mMockProviders =
193            new HashMap<>();
194
195    // all receivers
196    private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
197
198    // currently installed providers (with mocks replacing real providers)
199    private final ArrayList<LocationProviderInterface> mProviders =
200            new ArrayList<>();
201
202    // real providers, saved here when mocked out
203    private final HashMap<String, LocationProviderInterface> mRealProviders =
204            new HashMap<>();
205
206    // mapping from provider name to provider
207    private final HashMap<String, LocationProviderInterface> mProvidersByName =
208            new HashMap<>();
209
210    // mapping from provider name to all its UpdateRecords
211    private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
212            new HashMap<>();
213
214    private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
215
216    // mapping from provider name to last known location
217    private final HashMap<String, Location> mLastLocation = new HashMap<>();
218
219    // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
220    // locations stored here are not fudged for coarse permissions.
221    private final HashMap<String, Location> mLastLocationCoarseInterval =
222            new HashMap<>();
223
224    // all providers that operate over proxy, for authorizing incoming location and whitelisting
225    // throttling
226    private final ArrayList<LocationProviderProxy> mProxyProviders =
227            new ArrayList<>();
228
229    private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
230
231    private final ArrayMap<IGnssMeasurementsListener, Identity> mGnssMeasurementsListeners =
232            new ArrayMap<>();
233
234    private final ArrayMap<IGnssNavigationMessageListener, Identity>
235            mGnssNavigationMessageListeners = new ArrayMap<>();
236
237    // current active user on the device - other users are denied location data
238    private int mCurrentUserId = UserHandle.USER_SYSTEM;
239    private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
240
241    private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
242
243    private GnssLocationProvider.GnssBatchingProvider mGnssBatchingProvider;
244    private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
245    private IBatchedLocationCallback mGnssBatchingCallback;
246    private LinkedCallback mGnssBatchingDeathCallback;
247    private boolean mGnssBatchingInProgress = false;
248
249    public LocationManagerService(Context context) {
250        super();
251        mContext = context;
252        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
253
254        // Let the package manager query which are the default location
255        // providers as they get certain permissions granted by default.
256        PackageManagerInternal packageManagerInternal = LocalServices.getService(
257                PackageManagerInternal.class);
258        packageManagerInternal.setLocationPackagesProvider(
259                new PackageManagerInternal.PackagesProvider() {
260                    @Override
261                    public String[] getPackages(int userId) {
262                        return mContext.getResources().getStringArray(
263                                com.android.internal.R.array.config_locationProviderPackageNames);
264                    }
265                });
266
267        if (D) Log.d(TAG, "Constructed");
268
269        // most startup is deferred until systemRunning()
270    }
271
272    public void systemRunning() {
273        synchronized (mLock) {
274            if (D) Log.d(TAG, "systemRunning()");
275
276            // fetch package manager
277            mPackageManager = mContext.getPackageManager();
278
279            // fetch power manager
280            mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
281
282            // fetch activity manager
283            mActivityManager
284                    = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
285
286            // prepare worker thread
287            mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
288
289            // prepare mLocationHandler's dependents
290            mLocationFudger = new LocationFudger(mContext, mLocationHandler);
291            mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
292            mBlacklist.init();
293            mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
294
295            // Monitor for app ops mode changes.
296            AppOpsManager.OnOpChangedListener callback
297                    = new AppOpsManager.OnOpChangedInternalListener() {
298                public void onOpChanged(int op, String packageName) {
299                    synchronized (mLock) {
300                        for (Receiver receiver : mReceivers.values()) {
301                            receiver.updateMonitoring(true);
302                        }
303                        applyAllProviderRequirementsLocked();
304                    }
305                }
306            };
307            mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
308
309            PackageManager.OnPermissionsChangedListener permissionListener
310                    = new PackageManager.OnPermissionsChangedListener() {
311                @Override
312                public void onPermissionsChanged(final int uid) {
313                    synchronized (mLock) {
314                        applyAllProviderRequirementsLocked();
315                    }
316                }
317            };
318            mPackageManager.addOnPermissionsChangeListener(permissionListener);
319
320            // listen for background/foreground changes
321            ActivityManager.OnUidImportanceListener uidImportanceListener
322                    = new ActivityManager.OnUidImportanceListener() {
323                @Override
324                public void onUidImportance(int uid, int importance) {
325                    boolean foreground = isImportanceForeground(importance);
326                    HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
327                    synchronized (mLock) {
328                        for (Entry<String, ArrayList<UpdateRecord>> entry
329                                : mRecordsByProvider.entrySet()) {
330                            String provider = entry.getKey();
331                            for (UpdateRecord record : entry.getValue()) {
332                                if (record.mReceiver.mIdentity.mUid == uid
333                                        && record.mIsForegroundUid != foreground) {
334                                    if (D) Log.d(TAG, "request from uid " + uid + " is now "
335                                            + (foreground ? "foreground" : "background)"));
336                                    record.mIsForegroundUid = foreground;
337
338                                    if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
339                                        affectedProviders.add(provider);
340                                    }
341                                }
342                            }
343                        }
344                        for (String provider : affectedProviders) {
345                            applyRequirementsLocked(provider);
346                        }
347
348                        for (Entry<IGnssMeasurementsListener, Identity> entry
349                                : mGnssMeasurementsListeners.entrySet()) {
350                            if (entry.getValue().mUid == uid) {
351                                if (D) Log.d(TAG, "gnss measurements listener from uid " + uid
352                                    + " is now " + (foreground ? "foreground" : "background)"));
353                                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
354                                    mGnssMeasurementsProvider.addListener(entry.getKey());
355                                } else {
356                                    mGnssMeasurementsProvider.removeListener(entry.getKey());
357                                }
358                            }
359                        }
360
361                        for (Entry<IGnssNavigationMessageListener, Identity> entry
362                            : mGnssNavigationMessageListeners.entrySet()) {
363                            if (entry.getValue().mUid == uid) {
364                                if (D) Log.d(TAG, "gnss navigation message listener from uid "
365                                    + uid + " is now "
366                                    + (foreground ? "foreground" : "background)"));
367                                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
368                                    mGnssNavigationMessageProvider.addListener(entry.getKey());
369                                } else {
370                                    mGnssNavigationMessageProvider.removeListener(entry.getKey());
371                                }
372                            }
373                        }
374                    }
375
376                }
377            };
378            mActivityManager.addOnUidImportanceListener(uidImportanceListener,
379                    ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE);
380
381            mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
382            updateUserProfiles(mCurrentUserId);
383
384            updateBackgroundThrottlingWhitelistLocked();
385
386            // prepare providers
387            loadProvidersLocked();
388            updateProvidersLocked();
389        }
390
391        // listen for settings changes
392        mContext.getContentResolver().registerContentObserver(
393                Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
394                new ContentObserver(mLocationHandler) {
395                    @Override
396                    public void onChange(boolean selfChange) {
397                        synchronized (mLock) {
398                            updateProvidersLocked();
399                        }
400                    }
401                }, UserHandle.USER_ALL);
402        mContext.getContentResolver().registerContentObserver(
403                Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
404                true,
405                new ContentObserver(mLocationHandler) {
406                    @Override
407                    public void onChange(boolean selfChange) {
408                        synchronized (mLock) {
409                            updateProvidersLocked();
410                        }
411                    }
412                }, UserHandle.USER_ALL);
413        mContext.getContentResolver().registerContentObserver(
414            Settings.Global.getUriFor(
415                Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
416            true,
417            new ContentObserver(mLocationHandler) {
418                @Override
419                public void onChange(boolean selfChange) {
420                    synchronized (mLock) {
421                        updateBackgroundThrottlingWhitelistLocked();
422                        updateProvidersLocked();
423                    }
424                }
425            }, UserHandle.USER_ALL);
426        mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
427
428        // listen for user change
429        IntentFilter intentFilter = new IntentFilter();
430        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
431        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
432        intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
433        intentFilter.addAction(Intent.ACTION_SHUTDOWN);
434
435        mContext.registerReceiverAsUser(new BroadcastReceiver() {
436            @Override
437            public void onReceive(Context context, Intent intent) {
438                String action = intent.getAction();
439                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
440                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
441                } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
442                        || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
443                    updateUserProfiles(mCurrentUserId);
444                } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
445                    // shutdown only if UserId indicates whole system, not just one user
446                    if(D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId());
447                    if (getSendingUserId() == UserHandle.USER_ALL) {
448                        shutdownComponents();
449                    }
450                }
451            }
452        }, UserHandle.ALL, intentFilter, null, mLocationHandler);
453    }
454
455    private static boolean isImportanceForeground(int importance) {
456        return importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
457    }
458
459    /**
460     * Provides a way for components held by the {@link LocationManagerService} to clean-up
461     * gracefully on system's shutdown.
462     *
463     * NOTES:
464     * 1) Only provides a chance to clean-up on an opt-in basis. This guarantees back-compat
465     * support for components that do not wish to handle such event.
466     */
467    private void shutdownComponents() {
468        if(D) Log.d(TAG, "Shutting down components...");
469
470        LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
471        if (gpsProvider != null && gpsProvider.isEnabled()) {
472            gpsProvider.disable();
473        }
474
475        // it is needed to check if FLP HW provider is supported before accessing the instance, this
476        // avoids an exception to be thrown by the singleton factory method
477        if (FlpHardwareProvider.isSupported()) {
478            FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
479            flpHardwareProvider.cleanup();
480        }
481    }
482
483    /**
484     * Makes a list of userids that are related to the current user. This is
485     * relevant when using managed profiles. Otherwise the list only contains
486     * the current user.
487     *
488     * @param currentUserId the current user, who might have an alter-ego.
489     */
490    void updateUserProfiles(int currentUserId) {
491        int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
492        synchronized (mLock) {
493            mCurrentUserProfiles = profileIds;
494        }
495    }
496
497    /**
498     * Checks if the specified userId matches any of the current foreground
499     * users stored in mCurrentUserProfiles.
500     */
501    private boolean isCurrentProfile(int userId) {
502        synchronized (mLock) {
503            return ArrayUtils.contains(mCurrentUserProfiles, userId);
504        }
505    }
506
507    private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
508        PackageManager pm = mContext.getPackageManager();
509        String systemPackageName = mContext.getPackageName();
510        ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
511
512        List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
513                new Intent(FUSED_LOCATION_SERVICE_ACTION),
514                PackageManager.GET_META_DATA, mCurrentUserId);
515        for (ResolveInfo rInfo : rInfos) {
516            String packageName = rInfo.serviceInfo.packageName;
517
518            // Check that the signature is in the list of supported sigs. If it's not in
519            // this list the standard provider binding logic won't bind to it.
520            try {
521                PackageInfo pInfo;
522                pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
523                if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
524                    Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
525                            ", but has wrong signature, ignoring");
526                    continue;
527                }
528            } catch (NameNotFoundException e) {
529                Log.e(TAG, "missing package: " + packageName);
530                continue;
531            }
532
533            // Get the version info
534            if (rInfo.serviceInfo.metaData == null) {
535                Log.w(TAG, "Found fused provider without metadata: " + packageName);
536                continue;
537            }
538
539            int version = rInfo.serviceInfo.metaData.getInt(
540                    ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
541            if (version == 0) {
542                // This should be the fallback fused location provider.
543
544                // Make sure it's in the system partition.
545                if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
546                    if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
547                    continue;
548                }
549
550                // Check that the fallback is signed the same as the OS
551                // as a proxy for coreApp="true"
552                if (pm.checkSignatures(systemPackageName, packageName)
553                        != PackageManager.SIGNATURE_MATCH) {
554                    if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
555                            + packageName);
556                    continue;
557                }
558
559                // Found a valid fallback.
560                if (D) Log.d(TAG, "Found fallback provider: " + packageName);
561                return;
562            } else {
563                if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
564            }
565        }
566
567        throw new IllegalStateException("Unable to find a fused location provider that is in the "
568                + "system partition with version 0 and signed with the platform certificate. "
569                + "Such a package is needed to provide a default fused location provider in the "
570                + "event that no other fused location provider has been installed or is currently "
571                + "available. For example, coreOnly boot mode when decrypting the data "
572                + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
573    }
574
575    private void loadProvidersLocked() {
576        // create a passive location provider, which is always enabled
577        PassiveProvider passiveProvider = new PassiveProvider(this);
578        addProviderLocked(passiveProvider);
579        mEnabledProviders.add(passiveProvider.getName());
580        mPassiveProvider = passiveProvider;
581
582        if (GnssLocationProvider.isSupported()) {
583            // Create a gps location provider
584            GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
585                    mLocationHandler.getLooper());
586            mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
587            mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
588            mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
589            mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
590            mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
591            addProviderLocked(gnssProvider);
592            mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
593            mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
594            mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
595            mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
596        }
597
598        /*
599        Load package name(s) containing location provider support.
600        These packages can contain services implementing location providers:
601        Geocoder Provider, Network Location Provider, and
602        Fused Location Provider. They will each be searched for
603        service components implementing these providers.
604        The location framework also has support for installation
605        of new location providers at run-time. The new package does not
606        have to be explicitly listed here, however it must have a signature
607        that matches the signature of at least one package on this list.
608        */
609        Resources resources = mContext.getResources();
610        ArrayList<String> providerPackageNames = new ArrayList<>();
611        String[] pkgs = resources.getStringArray(
612                com.android.internal.R.array.config_locationProviderPackageNames);
613        if (D) Log.d(TAG, "certificates for location providers pulled from: " +
614                Arrays.toString(pkgs));
615        if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
616
617        ensureFallbackFusedProviderPresentLocked(providerPackageNames);
618
619        // bind to network provider
620        LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
621                mContext,
622                LocationManager.NETWORK_PROVIDER,
623                NETWORK_LOCATION_SERVICE_ACTION,
624                com.android.internal.R.bool.config_enableNetworkLocationOverlay,
625                com.android.internal.R.string.config_networkLocationProviderPackageName,
626                com.android.internal.R.array.config_locationProviderPackageNames,
627                mLocationHandler);
628        if (networkProvider != null) {
629            mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
630            mProxyProviders.add(networkProvider);
631            addProviderLocked(networkProvider);
632        } else {
633            Slog.w(TAG,  "no network location provider found");
634        }
635
636        // bind to fused provider
637        LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
638                mContext,
639                LocationManager.FUSED_PROVIDER,
640                FUSED_LOCATION_SERVICE_ACTION,
641                com.android.internal.R.bool.config_enableFusedLocationOverlay,
642                com.android.internal.R.string.config_fusedLocationProviderPackageName,
643                com.android.internal.R.array.config_locationProviderPackageNames,
644                mLocationHandler);
645        if (fusedLocationProvider != null) {
646            addProviderLocked(fusedLocationProvider);
647            mProxyProviders.add(fusedLocationProvider);
648            mEnabledProviders.add(fusedLocationProvider.getName());
649            mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
650        } else {
651            Slog.e(TAG, "no fused location provider found",
652                    new IllegalStateException("Location service needs a fused location provider"));
653        }
654
655        // bind to geocoder provider
656        mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
657                com.android.internal.R.bool.config_enableGeocoderOverlay,
658                com.android.internal.R.string.config_geocoderProviderPackageName,
659                com.android.internal.R.array.config_locationProviderPackageNames,
660                mLocationHandler);
661        if (mGeocodeProvider == null) {
662            Slog.e(TAG,  "no geocoder provider found");
663        }
664
665        // bind to fused hardware provider if supported
666        // in devices without support, requesting an instance of FlpHardwareProvider will raise an
667        // exception, so make sure we only do that when supported
668        FlpHardwareProvider flpHardwareProvider;
669        if (FlpHardwareProvider.isSupported()) {
670            flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
671            FusedProxy fusedProxy = FusedProxy.createAndBind(
672                    mContext,
673                    mLocationHandler,
674                    flpHardwareProvider.getLocationHardware(),
675                    com.android.internal.R.bool.config_enableHardwareFlpOverlay,
676                    com.android.internal.R.string.config_hardwareFlpPackageName,
677                    com.android.internal.R.array.config_locationProviderPackageNames);
678            if (fusedProxy == null) {
679                Slog.d(TAG, "Unable to bind FusedProxy.");
680            }
681        } else {
682            flpHardwareProvider = null;
683            Slog.d(TAG, "FLP HAL not supported");
684        }
685
686        // bind to geofence provider
687        GeofenceProxy provider = GeofenceProxy.createAndBind(
688                mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
689                com.android.internal.R.string.config_geofenceProviderPackageName,
690                com.android.internal.R.array.config_locationProviderPackageNames,
691                mLocationHandler,
692                mGpsGeofenceProxy,
693                flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
694        if (provider == null) {
695            Slog.d(TAG,  "Unable to bind FLP Geofence proxy.");
696        }
697
698        // bind to hardware activity recognition
699        boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
700        ActivityRecognitionHardware activityRecognitionHardware = null;
701        if (activityRecognitionHardwareIsSupported) {
702            activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
703        } else {
704            Slog.d(TAG, "Hardware Activity-Recognition not supported.");
705        }
706        ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
707                mContext,
708                mLocationHandler,
709                activityRecognitionHardwareIsSupported,
710                activityRecognitionHardware,
711                com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
712                com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
713                com.android.internal.R.array.config_locationProviderPackageNames);
714        if (proxy == null) {
715            Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
716        }
717
718        String[] testProviderStrings = resources.getStringArray(
719                com.android.internal.R.array.config_testLocationProviders);
720        for (String testProviderString : testProviderStrings) {
721            String fragments[] = testProviderString.split(",");
722            String name = fragments[0].trim();
723            if (mProvidersByName.get(name) != null) {
724                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
725            }
726            ProviderProperties properties = new ProviderProperties(
727                    Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
728                    Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
729                    Boolean.parseBoolean(fragments[3]) /* requiresCell */,
730                    Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
731                    Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
732                    Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
733                    Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
734                    Integer.parseInt(fragments[8]) /* powerRequirement */,
735                    Integer.parseInt(fragments[9]) /* accuracy */);
736            addTestProviderLocked(name, properties);
737        }
738    }
739
740    /**
741     * Called when the device's active user changes.
742     * @param userId the new active user's UserId
743     */
744    private void switchUser(int userId) {
745        if (mCurrentUserId == userId) {
746            return;
747        }
748        mBlacklist.switchUser(userId);
749        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
750        synchronized (mLock) {
751            mLastLocation.clear();
752            mLastLocationCoarseInterval.clear();
753            for (LocationProviderInterface p : mProviders) {
754                updateProviderListenersLocked(p.getName(), false);
755            }
756            mCurrentUserId = userId;
757            updateUserProfiles(userId);
758            updateProvidersLocked();
759        }
760    }
761
762    private static final class Identity {
763        final int mUid;
764        final int mPid;
765        final String mPackageName;
766
767        Identity(int uid, int pid, String packageName) {
768            mUid = uid;
769            mPid = pid;
770            mPackageName = packageName;
771        }
772    }
773
774    /**
775     * A wrapper class holding either an ILocationListener or a PendingIntent to receive
776     * location updates.
777     */
778    private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
779        final Identity mIdentity;
780        final int mAllowedResolutionLevel;  // resolution level allowed to receiver
781
782        final ILocationListener mListener;
783        final PendingIntent mPendingIntent;
784        final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
785        final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
786        final Object mKey;
787
788        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<>();
789
790        // True if app ops has started monitoring this receiver for locations.
791        boolean mOpMonitoring;
792        // True if app ops has started monitoring this receiver for high power (gps) locations.
793        boolean mOpHighPowerMonitoring;
794        int mPendingBroadcasts;
795        PowerManager.WakeLock mWakeLock;
796
797        Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
798                String packageName, WorkSource workSource, boolean hideFromAppOps) {
799            mListener = listener;
800            mPendingIntent = intent;
801            if (listener != null) {
802                mKey = listener.asBinder();
803            } else {
804                mKey = intent;
805            }
806            mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
807            mIdentity = new Identity(uid, pid, packageName);
808            if (workSource != null && workSource.size() <= 0) {
809                workSource = null;
810            }
811            mWorkSource = workSource;
812            mHideFromAppOps = hideFromAppOps;
813
814            updateMonitoring(true);
815
816            // construct/configure wakelock
817            mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
818            if (workSource == null) {
819                workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
820            }
821            mWakeLock.setWorkSource(workSource);
822        }
823
824        @Override
825        public boolean equals(Object otherObj) {
826            return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
827        }
828
829        @Override
830        public int hashCode() {
831            return mKey.hashCode();
832        }
833
834        @Override
835        public String toString() {
836            StringBuilder s = new StringBuilder();
837            s.append("Reciever[");
838            s.append(Integer.toHexString(System.identityHashCode(this)));
839            if (mListener != null) {
840                s.append(" listener");
841            } else {
842                s.append(" intent");
843            }
844            for (String p : mUpdateRecords.keySet()) {
845                s.append(" ").append(mUpdateRecords.get(p).toString());
846            }
847            s.append("]");
848            return s.toString();
849        }
850
851        /**
852         * Update AppOp monitoring for this receiver.
853         *
854         * @param allow If true receiver is currently active, if false it's been removed.
855         */
856        public void updateMonitoring(boolean allow) {
857            if (mHideFromAppOps) {
858                return;
859            }
860
861            boolean requestingLocation = false;
862            boolean requestingHighPowerLocation = false;
863            if (allow) {
864                // See if receiver has any enabled update records.  Also note if any update records
865                // are high power (has a high power provider with an interval under a threshold).
866                for (UpdateRecord updateRecord : mUpdateRecords.values()) {
867                    if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
868                        requestingLocation = true;
869                        LocationProviderInterface locationProvider
870                                = mProvidersByName.get(updateRecord.mProvider);
871                        ProviderProperties properties = locationProvider != null
872                                ? locationProvider.getProperties() : null;
873                        if (properties != null
874                                && properties.mPowerRequirement == Criteria.POWER_HIGH
875                                && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
876                            requestingHighPowerLocation = true;
877                            break;
878                        }
879                    }
880                }
881            }
882
883            // First update monitoring of any location request (including high power).
884            mOpMonitoring = updateMonitoring(
885                    requestingLocation,
886                    mOpMonitoring,
887                    AppOpsManager.OP_MONITOR_LOCATION);
888
889            // Now update monitoring of high power requests only.
890            boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
891            mOpHighPowerMonitoring = updateMonitoring(
892                    requestingHighPowerLocation,
893                    mOpHighPowerMonitoring,
894                    AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
895            if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
896                // Send an intent to notify that a high power request has been added/removed.
897                Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
898                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
899            }
900        }
901
902        /**
903         * Update AppOps monitoring for a single location request and op type.
904         *
905         * @param allowMonitoring True if monitoring is allowed for this request/op.
906         * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
907         * @param op AppOps code for the op to update.
908         * @return True if monitoring is on for this request/op after updating.
909         */
910        private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
911                int op) {
912            if (!currentlyMonitoring) {
913                if (allowMonitoring) {
914                    return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
915                            == AppOpsManager.MODE_ALLOWED;
916                }
917            } else {
918                if (!allowMonitoring
919                        || mAppOps.checkOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
920                        != AppOpsManager.MODE_ALLOWED) {
921                    mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
922                    return false;
923                }
924            }
925
926            return currentlyMonitoring;
927        }
928
929        public boolean isListener() {
930            return mListener != null;
931        }
932
933        public boolean isPendingIntent() {
934            return mPendingIntent != null;
935        }
936
937        public ILocationListener getListener() {
938            if (mListener != null) {
939                return mListener;
940            }
941            throw new IllegalStateException("Request for non-existent listener");
942        }
943
944        public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
945            if (mListener != null) {
946                try {
947                    synchronized (this) {
948                        // synchronize to ensure incrementPendingBroadcastsLocked()
949                        // is called before decrementPendingBroadcasts()
950                        mListener.onStatusChanged(provider, status, extras);
951                        // call this after broadcasting so we do not increment
952                        // if we throw an exeption.
953                        incrementPendingBroadcastsLocked();
954                    }
955                } catch (RemoteException e) {
956                    return false;
957                }
958            } else {
959                Intent statusChanged = new Intent();
960                statusChanged.putExtras(new Bundle(extras));
961                statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
962                try {
963                    synchronized (this) {
964                        // synchronize to ensure incrementPendingBroadcastsLocked()
965                        // is called before decrementPendingBroadcasts()
966                        mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
967                                getResolutionPermission(mAllowedResolutionLevel));
968                        // call this after broadcasting so we do not increment
969                        // if we throw an exeption.
970                        incrementPendingBroadcastsLocked();
971                    }
972                } catch (PendingIntent.CanceledException e) {
973                    return false;
974                }
975            }
976            return true;
977        }
978
979        public boolean callLocationChangedLocked(Location location) {
980            if (mListener != null) {
981                try {
982                    synchronized (this) {
983                        // synchronize to ensure incrementPendingBroadcastsLocked()
984                        // is called before decrementPendingBroadcasts()
985                        mListener.onLocationChanged(new Location(location));
986                        // call this after broadcasting so we do not increment
987                        // if we throw an exeption.
988                        incrementPendingBroadcastsLocked();
989                    }
990                } catch (RemoteException e) {
991                    return false;
992                }
993            } else {
994                Intent locationChanged = new Intent();
995                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
996                try {
997                    synchronized (this) {
998                        // synchronize to ensure incrementPendingBroadcastsLocked()
999                        // is called before decrementPendingBroadcasts()
1000                        mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
1001                                getResolutionPermission(mAllowedResolutionLevel));
1002                        // call this after broadcasting so we do not increment
1003                        // if we throw an exeption.
1004                        incrementPendingBroadcastsLocked();
1005                    }
1006                } catch (PendingIntent.CanceledException e) {
1007                    return false;
1008                }
1009            }
1010            return true;
1011        }
1012
1013        public boolean callProviderEnabledLocked(String provider, boolean enabled) {
1014            // First update AppOp monitoring.
1015            // An app may get/lose location access as providers are enabled/disabled.
1016            updateMonitoring(true);
1017
1018            if (mListener != null) {
1019                try {
1020                    synchronized (this) {
1021                        // synchronize to ensure incrementPendingBroadcastsLocked()
1022                        // is called before decrementPendingBroadcasts()
1023                        if (enabled) {
1024                            mListener.onProviderEnabled(provider);
1025                        } else {
1026                            mListener.onProviderDisabled(provider);
1027                        }
1028                        // call this after broadcasting so we do not increment
1029                        // if we throw an exeption.
1030                        incrementPendingBroadcastsLocked();
1031                    }
1032                } catch (RemoteException e) {
1033                    return false;
1034                }
1035            } else {
1036                Intent providerIntent = new Intent();
1037                providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1038                try {
1039                    synchronized (this) {
1040                        // synchronize to ensure incrementPendingBroadcastsLocked()
1041                        // is called before decrementPendingBroadcasts()
1042                        mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
1043                                getResolutionPermission(mAllowedResolutionLevel));
1044                        // call this after broadcasting so we do not increment
1045                        // if we throw an exeption.
1046                        incrementPendingBroadcastsLocked();
1047                    }
1048                } catch (PendingIntent.CanceledException e) {
1049                    return false;
1050                }
1051            }
1052            return true;
1053        }
1054
1055        @Override
1056        public void binderDied() {
1057            if (D) Log.d(TAG, "Location listener died");
1058
1059            synchronized (mLock) {
1060                removeUpdatesLocked(this);
1061            }
1062            synchronized (this) {
1063                clearPendingBroadcastsLocked();
1064            }
1065        }
1066
1067        @Override
1068        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1069                int resultCode, String resultData, Bundle resultExtras) {
1070            synchronized (this) {
1071                decrementPendingBroadcastsLocked();
1072            }
1073        }
1074
1075        // this must be called while synchronized by caller in a synchronized block
1076        // containing the sending of the broadcaset
1077        private void incrementPendingBroadcastsLocked() {
1078            if (mPendingBroadcasts++ == 0) {
1079                mWakeLock.acquire();
1080            }
1081        }
1082
1083        private void decrementPendingBroadcastsLocked() {
1084            if (--mPendingBroadcasts == 0) {
1085                if (mWakeLock.isHeld()) {
1086                    mWakeLock.release();
1087                }
1088            }
1089        }
1090
1091        public void clearPendingBroadcastsLocked() {
1092            if (mPendingBroadcasts > 0) {
1093                mPendingBroadcasts = 0;
1094                if (mWakeLock.isHeld()) {
1095                    mWakeLock.release();
1096                }
1097            }
1098        }
1099    }
1100
1101    @Override
1102    public void locationCallbackFinished(ILocationListener listener) {
1103        //Do not use getReceiverLocked here as that will add the ILocationListener to
1104        //the receiver list if it is not found.  If it is not found then the
1105        //LocationListener was removed when it had a pending broadcast and should
1106        //not be added back.
1107        synchronized (mLock) {
1108            IBinder binder = listener.asBinder();
1109            Receiver receiver = mReceivers.get(binder);
1110            if (receiver != null) {
1111                synchronized (receiver) {
1112                    // so wakelock calls will succeed
1113                    long identity = Binder.clearCallingIdentity();
1114                    receiver.decrementPendingBroadcastsLocked();
1115                    Binder.restoreCallingIdentity(identity);
1116                }
1117            }
1118        }
1119    }
1120
1121    /**
1122     * Returns the system information of the GNSS hardware.
1123     */
1124    @Override
1125    public int getGnssYearOfHardware() {
1126        if (mGnssSystemInfoProvider != null) {
1127            return mGnssSystemInfoProvider.getGnssYearOfHardware();
1128        } else {
1129            return 0;
1130        }
1131    }
1132
1133    /**
1134     * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
1135     * (try to) access GNSS information at this layer.
1136     */
1137    private boolean hasGnssPermissions(String packageName) {
1138        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1139        checkResolutionLevelIsSufficientForProviderUse(
1140                allowedResolutionLevel,
1141                LocationManager.GPS_PROVIDER);
1142
1143        int pid = Binder.getCallingPid();
1144        int uid = Binder.getCallingUid();
1145        long identity = Binder.clearCallingIdentity();
1146        boolean hasLocationAccess;
1147        try {
1148            hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1149        } finally {
1150            Binder.restoreCallingIdentity(identity);
1151        }
1152
1153        return hasLocationAccess;
1154    }
1155
1156    /**
1157     * Returns the GNSS batching size, if available.
1158     */
1159    @Override
1160    public int getGnssBatchSize(String packageName) {
1161        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1162                "Location Hardware permission not granted to access hardware batching");
1163
1164        if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
1165            return mGnssBatchingProvider.getSize();
1166        } else {
1167            return 0;
1168        }
1169    }
1170
1171    /**
1172     * Adds a callback for GNSS Batching events, if permissions allow, which are transported
1173     * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
1174     */
1175    @Override
1176    public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1177        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1178                "Location Hardware permission not granted to access hardware batching");
1179
1180        if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1181            return false;
1182        }
1183
1184        mGnssBatchingCallback = callback;
1185        mGnssBatchingDeathCallback = new LinkedCallback(callback);
1186        try {
1187            callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1188        } catch (RemoteException e) {
1189            // if the remote process registering the listener is already dead, just swallow the
1190            // exception and return
1191            Log.e(TAG, "Remote listener already died.", e);
1192            return false;
1193        }
1194
1195        return true;
1196    }
1197
1198    private class LinkedCallback implements IBinder.DeathRecipient {
1199        private final IBatchedLocationCallback mCallback;
1200
1201        public LinkedCallback(@NonNull IBatchedLocationCallback callback) {
1202            mCallback = callback;
1203        }
1204
1205        @NonNull
1206        public IBatchedLocationCallback getUnderlyingListener() {
1207            return mCallback;
1208        }
1209
1210        @Override
1211        public void binderDied() {
1212            Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1213            stopGnssBatch();
1214            removeGnssBatchingCallback();
1215        }
1216    }
1217
1218    /**
1219     * Removes callback for GNSS batching
1220     */
1221    @Override
1222    public void removeGnssBatchingCallback() {
1223        try {
1224            mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1225                    0 /* flags */);
1226        } catch (NoSuchElementException e) {
1227            // if the death callback isn't connected (it should be...), log error, swallow the
1228            // exception and return
1229            Log.e(TAG, "Couldn't unlink death callback.", e);
1230        }
1231        mGnssBatchingCallback = null;
1232        mGnssBatchingDeathCallback = null;
1233    }
1234
1235
1236    /**
1237     * Starts GNSS batching, if available.
1238     */
1239    @Override
1240    public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1241        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1242                "Location Hardware permission not granted to access hardware batching");
1243
1244        if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1245            return false;
1246        }
1247
1248        if (mGnssBatchingInProgress) {
1249            // Current design does not expect multiple starts to be called repeatedly
1250            Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1251            // Try to clean up anyway, and continue
1252            stopGnssBatch();
1253        }
1254
1255        mGnssBatchingInProgress = true;
1256        return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1257    }
1258
1259    /**
1260     * Flushes a GNSS batch in progress
1261     */
1262    @Override
1263    public void flushGnssBatch(String packageName) {
1264        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1265                "Location Hardware permission not granted to access hardware batching");
1266
1267        if (!hasGnssPermissions(packageName)) {
1268            Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1269            return;
1270        }
1271
1272        if (!mGnssBatchingInProgress) {
1273            Log.w(TAG, "flushGnssBatch called with no batch in progress");
1274        }
1275
1276        if (mGnssBatchingProvider != null) {
1277             mGnssBatchingProvider.flush();
1278        }
1279    }
1280
1281    /**
1282     * Stops GNSS batching
1283     */
1284    @Override
1285    public boolean stopGnssBatch() {
1286        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1287                "Location Hardware permission not granted to access hardware batching");
1288
1289        if (mGnssBatchingProvider != null) {
1290            mGnssBatchingInProgress = false;
1291            return mGnssBatchingProvider.stop();
1292        } else  {
1293            return false;
1294        }
1295    }
1296
1297    @Override
1298    public void reportLocationBatch(List<Location> locations) {
1299        checkCallerIsProvider();
1300
1301        // Currently used only for GNSS locations - update permissions check if changed
1302        if (isAllowedByCurrentUserSettingsLocked(LocationManager.GPS_PROVIDER)) {
1303            if (mGnssBatchingCallback == null) {
1304                Slog.e(TAG, "reportLocationBatch() called without active Callback");
1305                return;
1306            }
1307            try {
1308                mGnssBatchingCallback.onLocationBatch(locations);
1309            } catch (RemoteException e) {
1310                Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1311            }
1312        } else {
1313            Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
1314        }
1315    }
1316
1317    private void addProviderLocked(LocationProviderInterface provider) {
1318        mProviders.add(provider);
1319        mProvidersByName.put(provider.getName(), provider);
1320    }
1321
1322    private void removeProviderLocked(LocationProviderInterface provider) {
1323        provider.disable();
1324        mProviders.remove(provider);
1325        mProvidersByName.remove(provider.getName());
1326    }
1327
1328    /**
1329     * Returns "true" if access to the specified location provider is allowed by the current
1330     * user's settings. Access to all location providers is forbidden to non-location-provider
1331     * processes belonging to background users.
1332     *
1333     * @param provider the name of the location provider
1334     */
1335    private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
1336        if (mEnabledProviders.contains(provider)) {
1337            return true;
1338        }
1339        if (mDisabledProviders.contains(provider)) {
1340            return false;
1341        }
1342        // Use system settings
1343        ContentResolver resolver = mContext.getContentResolver();
1344
1345        return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
1346    }
1347
1348    /**
1349     * Returns "true" if access to the specified location provider is allowed by the specified
1350     * user's settings. Access to all location providers is forbidden to non-location-provider
1351     * processes belonging to background users.
1352     *
1353     * @param provider the name of the location provider
1354     * @param uid the requestor's UID
1355     */
1356    private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
1357        if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
1358            return false;
1359        }
1360        return isAllowedByCurrentUserSettingsLocked(provider);
1361    }
1362
1363    /**
1364     * Returns the permission string associated with the specified resolution level.
1365     *
1366     * @param resolutionLevel the resolution level
1367     * @return the permission string
1368     */
1369    private String getResolutionPermission(int resolutionLevel) {
1370        switch (resolutionLevel) {
1371            case RESOLUTION_LEVEL_FINE:
1372                return android.Manifest.permission.ACCESS_FINE_LOCATION;
1373            case RESOLUTION_LEVEL_COARSE:
1374                return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1375            default:
1376                return null;
1377        }
1378    }
1379
1380    /**
1381     * Returns the resolution level allowed to the given PID/UID pair.
1382     *
1383     * @param pid the PID
1384     * @param uid the UID
1385     * @return resolution level allowed to the pid/uid pair
1386     */
1387    private int getAllowedResolutionLevel(int pid, int uid) {
1388        if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1389                pid, uid) == PackageManager.PERMISSION_GRANTED) {
1390            return RESOLUTION_LEVEL_FINE;
1391        } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1392                pid, uid) == PackageManager.PERMISSION_GRANTED) {
1393            return RESOLUTION_LEVEL_COARSE;
1394        } else {
1395            return RESOLUTION_LEVEL_NONE;
1396        }
1397    }
1398
1399    /**
1400     * Returns the resolution level allowed to the caller
1401     *
1402     * @return resolution level allowed to caller
1403     */
1404    private int getCallerAllowedResolutionLevel() {
1405        return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1406    }
1407
1408    /**
1409     * Throw SecurityException if specified resolution level is insufficient to use geofences.
1410     *
1411     * @param allowedResolutionLevel resolution level allowed to caller
1412     */
1413    private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1414        if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1415            throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1416        }
1417    }
1418
1419    /**
1420     * Return the minimum resolution level required to use the specified location provider.
1421     *
1422     * @param provider the name of the location provider
1423     * @return minimum resolution level required for provider
1424     */
1425    private int getMinimumResolutionLevelForProviderUse(String provider) {
1426        if (LocationManager.GPS_PROVIDER.equals(provider) ||
1427                LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1428            // gps and passive providers require FINE permission
1429            return RESOLUTION_LEVEL_FINE;
1430        } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1431                LocationManager.FUSED_PROVIDER.equals(provider)) {
1432            // network and fused providers are ok with COARSE or FINE
1433            return RESOLUTION_LEVEL_COARSE;
1434        } else {
1435            // mock providers
1436            LocationProviderInterface lp = mMockProviders.get(provider);
1437            if (lp != null) {
1438                ProviderProperties properties = lp.getProperties();
1439                if (properties != null) {
1440                    if (properties.mRequiresSatellite) {
1441                        // provider requiring satellites require FINE permission
1442                        return RESOLUTION_LEVEL_FINE;
1443                    } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1444                        // provider requiring network and or cell require COARSE or FINE
1445                        return RESOLUTION_LEVEL_COARSE;
1446                    }
1447                }
1448            }
1449        }
1450        return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
1451    }
1452
1453    /**
1454     * Throw SecurityException if specified resolution level is insufficient to use the named
1455     * location provider.
1456     *
1457     * @param allowedResolutionLevel resolution level allowed to caller
1458     * @param providerName the name of the location provider
1459     */
1460    private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1461            String providerName) {
1462        int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1463        if (allowedResolutionLevel < requiredResolutionLevel) {
1464            switch (requiredResolutionLevel) {
1465                case RESOLUTION_LEVEL_FINE:
1466                    throw new SecurityException("\"" + providerName + "\" location provider " +
1467                            "requires ACCESS_FINE_LOCATION permission.");
1468                case RESOLUTION_LEVEL_COARSE:
1469                    throw new SecurityException("\"" + providerName + "\" location provider " +
1470                            "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1471                default:
1472                    throw new SecurityException("Insufficient permission for \"" + providerName +
1473                            "\" location provider.");
1474            }
1475        }
1476    }
1477
1478    /**
1479     * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1480     * for battery).
1481     */
1482    private void checkDeviceStatsAllowed() {
1483        mContext.enforceCallingOrSelfPermission(
1484                android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1485    }
1486
1487    private void checkUpdateAppOpsAllowed() {
1488        mContext.enforceCallingOrSelfPermission(
1489                android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1490    }
1491
1492    public static int resolutionLevelToOp(int allowedResolutionLevel) {
1493        if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1494            if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
1495                return AppOpsManager.OP_COARSE_LOCATION;
1496            } else {
1497                return AppOpsManager.OP_FINE_LOCATION;
1498            }
1499        }
1500        return -1;
1501    }
1502
1503    boolean reportLocationAccessNoThrow(
1504            int pid, int uid, String packageName, int allowedResolutionLevel) {
1505        int op = resolutionLevelToOp(allowedResolutionLevel);
1506        if (op >= 0) {
1507            if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1508                return false;
1509            }
1510        }
1511
1512        return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
1513    }
1514
1515    boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
1516        int op = resolutionLevelToOp(allowedResolutionLevel);
1517        if (op >= 0) {
1518            if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1519                return false;
1520            }
1521        }
1522
1523        return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
1524    }
1525
1526    /**
1527     * Returns all providers by name, including passive, but excluding
1528     * fused, also including ones that are not permitted to
1529     * be accessed by the calling activity or are currently disabled.
1530     */
1531    @Override
1532    public List<String> getAllProviders() {
1533        ArrayList<String> out;
1534        synchronized (mLock) {
1535            out = new ArrayList<>(mProviders.size());
1536            for (LocationProviderInterface provider : mProviders) {
1537                String name = provider.getName();
1538                if (LocationManager.FUSED_PROVIDER.equals(name)) {
1539                    continue;
1540                }
1541                out.add(name);
1542            }
1543        }
1544
1545        if (D) Log.d(TAG, "getAllProviders()=" + out);
1546        return out;
1547    }
1548
1549    /**
1550     * Return all providers by name, that match criteria and are optionally
1551     * enabled.
1552     * Can return passive provider, but never returns fused provider.
1553     */
1554    @Override
1555    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
1556        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1557        ArrayList<String> out;
1558        int uid = Binder.getCallingUid();
1559        long identity = Binder.clearCallingIdentity();
1560        try {
1561            synchronized (mLock) {
1562                out = new ArrayList<>(mProviders.size());
1563                for (LocationProviderInterface provider : mProviders) {
1564                    String name = provider.getName();
1565                    if (LocationManager.FUSED_PROVIDER.equals(name)) {
1566                        continue;
1567                    }
1568                    if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
1569                        if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
1570                            continue;
1571                        }
1572                        if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1573                                name, provider.getProperties(), criteria)) {
1574                            continue;
1575                        }
1576                        out.add(name);
1577                    }
1578                }
1579            }
1580        } finally {
1581            Binder.restoreCallingIdentity(identity);
1582        }
1583
1584        if (D) Log.d(TAG, "getProviders()=" + out);
1585        return out;
1586    }
1587
1588    /**
1589     * Return the name of the best provider given a Criteria object.
1590     * This method has been deprecated from the public API,
1591     * and the whole LocationProvider (including #meetsCriteria)
1592     * has been deprecated as well. So this method now uses
1593     * some simplified logic.
1594     */
1595    @Override
1596    public String getBestProvider(Criteria criteria, boolean enabledOnly) {
1597        String result = null;
1598
1599        List<String> providers = getProviders(criteria, enabledOnly);
1600        if (!providers.isEmpty()) {
1601            result = pickBest(providers);
1602            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1603            return result;
1604        }
1605        providers = getProviders(null, enabledOnly);
1606        if (!providers.isEmpty()) {
1607            result = pickBest(providers);
1608            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1609            return result;
1610        }
1611
1612        if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1613        return null;
1614    }
1615
1616    private String pickBest(List<String> providers) {
1617        if (providers.contains(LocationManager.GPS_PROVIDER)) {
1618            return LocationManager.GPS_PROVIDER;
1619        } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1620            return LocationManager.NETWORK_PROVIDER;
1621        } else {
1622            return providers.get(0);
1623        }
1624    }
1625
1626    @Override
1627    public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1628        LocationProviderInterface p = mProvidersByName.get(provider);
1629        if (p == null) {
1630            throw new IllegalArgumentException("provider=" + provider);
1631        }
1632
1633        boolean result = LocationProvider.propertiesMeetCriteria(
1634                p.getName(), p.getProperties(), criteria);
1635        if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1636        return result;
1637    }
1638
1639    private void updateProvidersLocked() {
1640        boolean changesMade = false;
1641        for (int i = mProviders.size() - 1; i >= 0; i--) {
1642            LocationProviderInterface p = mProviders.get(i);
1643            boolean isEnabled = p.isEnabled();
1644            String name = p.getName();
1645            boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
1646            if (isEnabled && !shouldBeEnabled) {
1647                updateProviderListenersLocked(name, false);
1648                // If any provider has been disabled, clear all last locations for all providers.
1649                // This is to be on the safe side in case a provider has location derived from
1650                // this disabled provider.
1651                mLastLocation.clear();
1652                mLastLocationCoarseInterval.clear();
1653                changesMade = true;
1654            } else if (!isEnabled && shouldBeEnabled) {
1655                updateProviderListenersLocked(name, true);
1656                changesMade = true;
1657            }
1658        }
1659        if (changesMade) {
1660            mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1661                    UserHandle.ALL);
1662            mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1663                    UserHandle.ALL);
1664        }
1665    }
1666
1667    private void updateProviderListenersLocked(String provider, boolean enabled) {
1668        int listeners = 0;
1669
1670        LocationProviderInterface p = mProvidersByName.get(provider);
1671        if (p == null) return;
1672
1673        ArrayList<Receiver> deadReceivers = null;
1674
1675        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1676        if (records != null) {
1677            for (UpdateRecord record : records) {
1678                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
1679                    // Sends a notification message to the receiver
1680                    if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1681                        if (deadReceivers == null) {
1682                            deadReceivers = new ArrayList<>();
1683                        }
1684                        deadReceivers.add(record.mReceiver);
1685                    }
1686                    listeners++;
1687                }
1688            }
1689        }
1690
1691        if (deadReceivers != null) {
1692            for (int i = deadReceivers.size() - 1; i >= 0; i--) {
1693                removeUpdatesLocked(deadReceivers.get(i));
1694            }
1695        }
1696
1697        if (enabled) {
1698            p.enable();
1699            if (listeners > 0) {
1700                applyRequirementsLocked(provider);
1701            }
1702        } else {
1703            p.disable();
1704        }
1705    }
1706
1707    private void applyRequirementsLocked(String provider) {
1708        LocationProviderInterface p = mProvidersByName.get(provider);
1709        if (p == null) return;
1710
1711        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1712        WorkSource worksource = new WorkSource();
1713        ProviderRequest providerRequest = new ProviderRequest();
1714
1715        ContentResolver resolver = mContext.getContentResolver();
1716        long backgroundThrottleInterval = Settings.Global.getLong(
1717                resolver,
1718                Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1719                DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
1720
1721        if (records != null) {
1722            for (UpdateRecord record : records) {
1723                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
1724                    if (checkLocationAccess(
1725                            record.mReceiver.mIdentity.mPid,
1726                            record.mReceiver.mIdentity.mUid,
1727                            record.mReceiver.mIdentity.mPackageName,
1728                            record.mReceiver.mAllowedResolutionLevel)) {
1729                        LocationRequest locationRequest = record.mRequest;
1730                        long interval = locationRequest.getInterval();
1731
1732                        if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
1733                            if (!record.mIsForegroundUid) {
1734                                interval = Math.max(interval, backgroundThrottleInterval);
1735                            }
1736                            if (interval != locationRequest.getInterval()) {
1737                                locationRequest = new LocationRequest(locationRequest);
1738                                locationRequest.setInterval(interval);
1739                            }
1740                        }
1741
1742                        providerRequest.locationRequests.add(locationRequest);
1743                        if (interval < providerRequest.interval) {
1744                            providerRequest.reportLocation = true;
1745                            providerRequest.interval = interval;
1746                        }
1747                    }
1748                }
1749            }
1750
1751            if (providerRequest.reportLocation) {
1752                // calculate who to blame for power
1753                // This is somewhat arbitrary. We pick a threshold interval
1754                // that is slightly higher that the minimum interval, and
1755                // spread the blame across all applications with a request
1756                // under that threshold.
1757                long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1758                for (UpdateRecord record : records) {
1759                    if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
1760                        LocationRequest locationRequest = record.mRequest;
1761
1762                        // Don't assign battery blame for update records whose
1763                        // client has no permission to receive location data.
1764                        if (!providerRequest.locationRequests.contains(locationRequest)) {
1765                            continue;
1766                        }
1767
1768                        if (locationRequest.getInterval() <= thresholdInterval) {
1769                            if (record.mReceiver.mWorkSource != null
1770                                    && record.mReceiver.mWorkSource.size() > 0
1771                                    && record.mReceiver.mWorkSource.getName(0) != null) {
1772                                // Assign blame to another work source.
1773                                // Can only assign blame if the WorkSource contains names.
1774                                worksource.add(record.mReceiver.mWorkSource);
1775                            } else {
1776                                // Assign blame to caller.
1777                                worksource.add(
1778                                        record.mReceiver.mIdentity.mUid,
1779                                        record.mReceiver.mIdentity.mPackageName);
1780                            }
1781                        }
1782                    }
1783                }
1784            }
1785        }
1786
1787        if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1788        p.setRequest(providerRequest, worksource);
1789    }
1790
1791    @Override
1792    public String[] getBackgroundThrottlingWhitelist() {
1793        synchronized (mLock) {
1794            return mBackgroundThrottlePackageWhitelist.toArray(
1795                new String[mBackgroundThrottlePackageWhitelist.size()]);
1796        }
1797    }
1798
1799    private void updateBackgroundThrottlingWhitelistLocked() {
1800        String setting = Settings.Global.getString(
1801            mContext.getContentResolver(),
1802            Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
1803        if (setting == null) {
1804            setting = "";
1805        }
1806
1807        mBackgroundThrottlePackageWhitelist.clear();
1808        mBackgroundThrottlePackageWhitelist.addAll(
1809            SystemConfig.getInstance().getAllowUnthrottledLocation());
1810        mBackgroundThrottlePackageWhitelist.addAll(
1811            Arrays.asList(setting.split(",")));
1812    }
1813
1814    private boolean isThrottlingExemptLocked(Identity identity) {
1815        if (identity.mUid == Process.SYSTEM_UID) {
1816            return true;
1817        }
1818
1819        if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
1820            return true;
1821        }
1822
1823        for (LocationProviderProxy provider : mProxyProviders) {
1824            if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
1825                return true;
1826            }
1827        }
1828
1829        return false;
1830    }
1831
1832    private class UpdateRecord {
1833        final String mProvider;
1834        final LocationRequest mRequest;
1835        final Receiver mReceiver;
1836        boolean mIsForegroundUid;
1837        Location mLastFixBroadcast;
1838        long mLastStatusBroadcast;
1839
1840        /**
1841         * Note: must be constructed with lock held.
1842         */
1843        UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
1844            mProvider = provider;
1845            mRequest = request;
1846            mReceiver = receiver;
1847            mIsForegroundUid = isImportanceForeground(
1848                    mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
1849
1850            ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1851            if (records == null) {
1852                records = new ArrayList<>();
1853                mRecordsByProvider.put(provider, records);
1854            }
1855            if (!records.contains(this)) {
1856                records.add(this);
1857            }
1858
1859            // Update statistics for historical location requests by package/provider
1860            mRequestStatistics.startRequesting(
1861                    mReceiver.mIdentity.mPackageName, provider, request.getInterval());
1862        }
1863
1864        /**
1865         * Method to be called when a record will no longer be used.
1866         */
1867        void disposeLocked(boolean removeReceiver) {
1868            mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
1869
1870            // remove from mRecordsByProvider
1871            ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1872            if (globalRecords != null) {
1873                globalRecords.remove(this);
1874            }
1875
1876            if (!removeReceiver) return;  // the caller will handle the rest
1877
1878            // remove from Receiver#mUpdateRecords
1879            HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1880            if (receiverRecords != null) {
1881                receiverRecords.remove(this.mProvider);
1882
1883                // and also remove the Receiver if it has no more update records
1884                if (receiverRecords.size() == 0) {
1885                    removeUpdatesLocked(mReceiver);
1886                }
1887            }
1888        }
1889
1890        @Override
1891        public String toString() {
1892            return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
1893                    + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground" : " background")
1894                    + ")" + " " + mRequest + "]";
1895        }
1896    }
1897
1898    private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
1899            String packageName, WorkSource workSource, boolean hideFromAppOps) {
1900        IBinder binder = listener.asBinder();
1901        Receiver receiver = mReceivers.get(binder);
1902        if (receiver == null) {
1903            receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1904                    hideFromAppOps);
1905            try {
1906                receiver.getListener().asBinder().linkToDeath(receiver, 0);
1907            } catch (RemoteException e) {
1908                Slog.e(TAG, "linkToDeath failed:", e);
1909                return null;
1910            }
1911            mReceivers.put(binder, receiver);
1912        }
1913        return receiver;
1914    }
1915
1916    private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
1917            WorkSource workSource, boolean hideFromAppOps) {
1918        Receiver receiver = mReceivers.get(intent);
1919        if (receiver == null) {
1920            receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1921                    hideFromAppOps);
1922            mReceivers.put(intent, receiver);
1923        }
1924        return receiver;
1925    }
1926
1927    /**
1928     * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1929     * and consistency requirements.
1930     *
1931     * @param request the LocationRequest from which to create a sanitized version
1932     * @return a version of request that meets the given resolution and consistency requirements
1933     * @hide
1934     */
1935    private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1936        LocationRequest sanitizedRequest = new LocationRequest(request);
1937        if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1938            switch (sanitizedRequest.getQuality()) {
1939                case LocationRequest.ACCURACY_FINE:
1940                    sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
1941                    break;
1942                case LocationRequest.POWER_HIGH:
1943                    sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
1944                    break;
1945            }
1946            // throttle
1947            if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1948                sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1949            }
1950            if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1951                sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1952            }
1953        }
1954        // make getFastestInterval() the minimum of interval and fastest interval
1955        if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
1956            request.setFastestInterval(request.getInterval());
1957        }
1958        return sanitizedRequest;
1959    }
1960
1961    private void checkPackageName(String packageName) {
1962        if (packageName == null) {
1963            throw new SecurityException("invalid package name: " + packageName);
1964        }
1965        int uid = Binder.getCallingUid();
1966        String[] packages = mPackageManager.getPackagesForUid(uid);
1967        if (packages == null) {
1968            throw new SecurityException("invalid UID " + uid);
1969        }
1970        for (String pkg : packages) {
1971            if (packageName.equals(pkg)) return;
1972        }
1973        throw new SecurityException("invalid package name: " + packageName);
1974    }
1975
1976    private void checkPendingIntent(PendingIntent intent) {
1977        if (intent == null) {
1978            throw new IllegalArgumentException("invalid pending intent: " + intent);
1979        }
1980    }
1981
1982    private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
1983            int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
1984        if (intent == null && listener == null) {
1985            throw new IllegalArgumentException("need either listener or intent");
1986        } else if (intent != null && listener != null) {
1987            throw new IllegalArgumentException("cannot register both listener and intent");
1988        } else if (intent != null) {
1989            checkPendingIntent(intent);
1990            return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
1991        } else {
1992            return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
1993        }
1994    }
1995
1996    @Override
1997    public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1998            PendingIntent intent, String packageName) {
1999        if (request == null) request = DEFAULT_LOCATION_REQUEST;
2000        checkPackageName(packageName);
2001        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2002        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2003                request.getProvider());
2004        WorkSource workSource = request.getWorkSource();
2005        if (workSource != null && workSource.size() > 0) {
2006            checkDeviceStatsAllowed();
2007        }
2008        boolean hideFromAppOps = request.getHideFromAppOps();
2009        if (hideFromAppOps) {
2010            checkUpdateAppOpsAllowed();
2011        }
2012        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
2013
2014        final int pid = Binder.getCallingPid();
2015        final int uid = Binder.getCallingUid();
2016        // providers may use public location API's, need to clear identity
2017        long identity = Binder.clearCallingIdentity();
2018        try {
2019            // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2020            // a location.
2021            checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
2022
2023            synchronized (mLock) {
2024                Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
2025                        packageName, workSource, hideFromAppOps);
2026                requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
2027            }
2028        } finally {
2029            Binder.restoreCallingIdentity(identity);
2030        }
2031    }
2032
2033    private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
2034            int pid, int uid, String packageName) {
2035        // Figure out the provider. Either its explicitly request (legacy use cases), or
2036        // use the fused provider
2037        if (request == null) request = DEFAULT_LOCATION_REQUEST;
2038        String name = request.getProvider();
2039        if (name == null) {
2040            throw new IllegalArgumentException("provider name must not be null");
2041        }
2042
2043        LocationProviderInterface provider = mProvidersByName.get(name);
2044        if (provider == null) {
2045            throw new IllegalArgumentException("provider doesn't exist: " + name);
2046        }
2047
2048        UpdateRecord record = new UpdateRecord(name, request, receiver);
2049        if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2050                + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2051                + (record.mIsForegroundUid ? "foreground" : "background")
2052                + (isThrottlingExemptLocked(receiver.mIdentity)
2053                    ? " [whitelisted]" : "") + ")");
2054
2055        UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2056        if (oldRecord != null) {
2057            oldRecord.disposeLocked(false);
2058        }
2059
2060        boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
2061        if (isProviderEnabled) {
2062            applyRequirementsLocked(name);
2063        } else {
2064            // Notify the listener that updates are currently disabled
2065            receiver.callProviderEnabledLocked(name, false);
2066        }
2067        // Update the monitoring here just in case multiple location requests were added to the
2068        // same receiver (this request may be high power and the initial might not have been).
2069        receiver.updateMonitoring(true);
2070    }
2071
2072    @Override
2073    public void removeUpdates(ILocationListener listener, PendingIntent intent,
2074            String packageName) {
2075        checkPackageName(packageName);
2076
2077        final int pid = Binder.getCallingPid();
2078        final int uid = Binder.getCallingUid();
2079
2080        synchronized (mLock) {
2081            WorkSource workSource = null;
2082            boolean hideFromAppOps = false;
2083            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
2084                    packageName, workSource, hideFromAppOps);
2085
2086            // providers may use public location API's, need to clear identity
2087            long identity = Binder.clearCallingIdentity();
2088            try {
2089                removeUpdatesLocked(receiver);
2090            } finally {
2091                Binder.restoreCallingIdentity(identity);
2092            }
2093        }
2094    }
2095
2096    private void removeUpdatesLocked(Receiver receiver) {
2097        if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
2098
2099        if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2100            receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2101            synchronized (receiver) {
2102                receiver.clearPendingBroadcastsLocked();
2103            }
2104        }
2105
2106        receiver.updateMonitoring(false);
2107
2108        // Record which providers were associated with this listener
2109        HashSet<String> providers = new HashSet<>();
2110        HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2111        if (oldRecords != null) {
2112            // Call dispose() on the obsolete update records.
2113            for (UpdateRecord record : oldRecords.values()) {
2114                // Update statistics for historical location requests by package/provider
2115                record.disposeLocked(false);
2116            }
2117            // Accumulate providers
2118            providers.addAll(oldRecords.keySet());
2119        }
2120
2121        // update provider
2122        for (String provider : providers) {
2123            // If provider is already disabled, don't need to do anything
2124            if (!isAllowedByCurrentUserSettingsLocked(provider)) {
2125                continue;
2126            }
2127
2128            applyRequirementsLocked(provider);
2129        }
2130    }
2131
2132    private void applyAllProviderRequirementsLocked() {
2133        for (LocationProviderInterface p : mProviders) {
2134            // If provider is already disabled, don't need to do anything
2135            if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
2136                continue;
2137            }
2138
2139            applyRequirementsLocked(p.getName());
2140        }
2141    }
2142
2143    @Override
2144    public Location getLastLocation(LocationRequest request, String packageName) {
2145        if (D) Log.d(TAG, "getLastLocation: " + request);
2146        if (request == null) request = DEFAULT_LOCATION_REQUEST;
2147        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2148        checkPackageName(packageName);
2149        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2150                request.getProvider());
2151        // no need to sanitize this request, as only the provider name is used
2152
2153        final int pid = Binder.getCallingPid();
2154        final int uid = Binder.getCallingUid();
2155        final long identity = Binder.clearCallingIdentity();
2156        try {
2157            if (mBlacklist.isBlacklisted(packageName)) {
2158                if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
2159                        packageName);
2160                return null;
2161            }
2162
2163            if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
2164                if (D) Log.d(TAG, "not returning last loc for no op app: " +
2165                        packageName);
2166                return null;
2167            }
2168
2169            synchronized (mLock) {
2170                // Figure out the provider. Either its explicitly request (deprecated API's),
2171                // or use the fused provider
2172                String name = request.getProvider();
2173                if (name == null) name = LocationManager.FUSED_PROVIDER;
2174                LocationProviderInterface provider = mProvidersByName.get(name);
2175                if (provider == null) return null;
2176
2177                if (!isAllowedByUserSettingsLocked(name, uid)) return null;
2178
2179                Location location;
2180                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2181                    // Make sure that an app with coarse permissions can't get frequent location
2182                    // updates by calling LocationManager.getLastKnownLocation repeatedly.
2183                    location = mLastLocationCoarseInterval.get(name);
2184                } else {
2185                    location = mLastLocation.get(name);
2186                }
2187                if (location == null) {
2188                    return null;
2189                }
2190                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2191                    Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2192                    if (noGPSLocation != null) {
2193                        return new Location(mLocationFudger.getOrCreate(noGPSLocation));
2194                    }
2195                } else {
2196                    return new Location(location);
2197                }
2198            }
2199            return null;
2200        } finally {
2201            Binder.restoreCallingIdentity(identity);
2202        }
2203    }
2204
2205    @Override
2206    public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2207            String packageName) {
2208        if (request == null) request = DEFAULT_LOCATION_REQUEST;
2209        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2210        checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
2211        checkPendingIntent(intent);
2212        checkPackageName(packageName);
2213        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2214                request.getProvider());
2215        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
2216
2217        if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
2218
2219        // geo-fence manager uses the public location API, need to clear identity
2220        int uid = Binder.getCallingUid();
2221        // TODO: http://b/23822629
2222        if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
2223            // temporary measure until geofences work for secondary users
2224            Log.w(TAG, "proximity alerts are currently available only to the primary user");
2225            return;
2226        }
2227        long identity = Binder.clearCallingIdentity();
2228        try {
2229            mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2230                    uid, packageName);
2231        } finally {
2232            Binder.restoreCallingIdentity(identity);
2233        }
2234    }
2235
2236    @Override
2237    public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
2238        checkPendingIntent(intent);
2239        checkPackageName(packageName);
2240
2241        if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2242
2243        // geo-fence manager uses the public location API, need to clear identity
2244        long identity = Binder.clearCallingIdentity();
2245        try {
2246            mGeofenceManager.removeFence(geofence, intent);
2247        } finally {
2248            Binder.restoreCallingIdentity(identity);
2249        }
2250    }
2251
2252
2253    @Override
2254    public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
2255        if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
2256            return false;
2257        }
2258
2259        try {
2260            mGnssStatusProvider.registerGnssStatusCallback(callback);
2261        } catch (RemoteException e) {
2262            Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
2263            return false;
2264        }
2265        return true;
2266    }
2267
2268    @Override
2269    public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
2270        synchronized (mLock) {
2271            try {
2272                mGnssStatusProvider.unregisterGnssStatusCallback(callback);
2273            } catch (Exception e) {
2274                Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
2275            }
2276        }
2277    }
2278
2279    @Override
2280    public boolean addGnssMeasurementsListener(
2281            IGnssMeasurementsListener listener,
2282            String packageName) {
2283        if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2284            return false;
2285        }
2286
2287        synchronized (mLock) {
2288            Identity callerIdentity
2289                    = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
2290            mGnssMeasurementsListeners.put(listener, callerIdentity);
2291            long identity = Binder.clearCallingIdentity();
2292            try {
2293                if (isThrottlingExemptLocked(callerIdentity)
2294                        || isImportanceForeground(
2295                                mActivityManager.getPackageImportance(packageName))) {
2296                    return mGnssMeasurementsProvider.addListener(listener);
2297                }
2298            } finally {
2299                Binder.restoreCallingIdentity(identity);
2300            }
2301
2302            return true;
2303        }
2304    }
2305
2306    @Override
2307    public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
2308        if (mGnssMeasurementsProvider != null) {
2309            synchronized (mLock) {
2310                mGnssMeasurementsListeners.remove(listener);
2311                mGnssMeasurementsProvider.removeListener(listener);
2312            }
2313        }
2314    }
2315
2316    @Override
2317    public boolean addGnssNavigationMessageListener(
2318            IGnssNavigationMessageListener listener,
2319            String packageName) {
2320        if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
2321            return false;
2322        }
2323
2324        synchronized (mLock) {
2325            Identity callerIdentity
2326                = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
2327            mGnssNavigationMessageListeners.put(listener, callerIdentity);
2328            long identity = Binder.clearCallingIdentity();
2329            try {
2330                if (isThrottlingExemptLocked(callerIdentity)
2331                        || isImportanceForeground(
2332                                mActivityManager.getPackageImportance(packageName))) {
2333                    return mGnssNavigationMessageProvider.addListener(listener);
2334                }
2335            } finally {
2336                Binder.restoreCallingIdentity(identity);
2337            }
2338
2339            return true;
2340        }
2341    }
2342
2343    @Override
2344    public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2345        if (mGnssNavigationMessageProvider != null) {
2346            synchronized (mLock) {
2347                mGnssNavigationMessageListeners.remove(listener);
2348                mGnssNavigationMessageProvider.removeListener(listener);
2349            }
2350        }
2351    }
2352
2353    @Override
2354    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
2355        if (provider == null) {
2356            // throw NullPointerException to remain compatible with previous implementation
2357            throw new NullPointerException();
2358        }
2359        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2360                provider);
2361
2362        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
2363        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
2364                != PackageManager.PERMISSION_GRANTED)) {
2365            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2366        }
2367
2368        synchronized (mLock) {
2369            LocationProviderInterface p = mProvidersByName.get(provider);
2370            if (p == null) return false;
2371
2372            return p.sendExtraCommand(command, extras);
2373        }
2374    }
2375
2376    @Override
2377    public boolean sendNiResponse(int notifId, int userResponse) {
2378        if (Binder.getCallingUid() != Process.myUid()) {
2379            throw new SecurityException(
2380                    "calling sendNiResponse from outside of the system is not allowed");
2381        }
2382        try {
2383            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
2384        } catch (RemoteException e) {
2385            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
2386            return false;
2387        }
2388    }
2389
2390    /**
2391     * @return null if the provider does not exist
2392     * @throws SecurityException if the provider is not allowed to be
2393     * accessed by the caller
2394     */
2395    @Override
2396    public ProviderProperties getProviderProperties(String provider) {
2397        if (mProvidersByName.get(provider) == null) {
2398            return null;
2399        }
2400
2401        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2402                provider);
2403
2404        LocationProviderInterface p;
2405        synchronized (mLock) {
2406            p = mProvidersByName.get(provider);
2407        }
2408
2409        if (p == null) return null;
2410        return p.getProperties();
2411    }
2412
2413    /**
2414     * @return null if the provider does not exist
2415     * @throws SecurityException if the provider is not allowed to be
2416     * accessed by the caller
2417     */
2418    @Override
2419    public String getNetworkProviderPackage() {
2420        LocationProviderInterface p;
2421        synchronized (mLock) {
2422            if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2423                return null;
2424            }
2425            p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2426        }
2427
2428        if (p instanceof LocationProviderProxy) {
2429            return ((LocationProviderProxy) p).getConnectedPackageName();
2430        }
2431        return null;
2432    }
2433
2434    @Override
2435    public boolean isProviderEnabled(String provider) {
2436        // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2437        // so we discourage its use
2438        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2439
2440        int uid = Binder.getCallingUid();
2441        long identity = Binder.clearCallingIdentity();
2442        try {
2443            synchronized (mLock) {
2444                LocationProviderInterface p = mProvidersByName.get(provider);
2445                return p != null && isAllowedByUserSettingsLocked(provider, uid);
2446            }
2447        } finally {
2448            Binder.restoreCallingIdentity(identity);
2449        }
2450    }
2451
2452    /**
2453     * Returns "true" if the UID belongs to a bound location provider.
2454     *
2455     * @param uid the uid
2456     * @return true if uid belongs to a bound location provider
2457     */
2458    private boolean isUidALocationProvider(int uid) {
2459        if (uid == Process.SYSTEM_UID) {
2460            return true;
2461        }
2462        if (mGeocodeProvider != null) {
2463            if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
2464        }
2465        for (LocationProviderProxy proxy : mProxyProviders) {
2466            if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
2467        }
2468        return false;
2469    }
2470
2471    private void checkCallerIsProvider() {
2472        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2473                == PackageManager.PERMISSION_GRANTED) {
2474            return;
2475        }
2476
2477        // Previously we only used the INSTALL_LOCATION_PROVIDER
2478        // check. But that is system or signature
2479        // protection level which is not flexible enough for
2480        // providers installed oustide the system image. So
2481        // also allow providers with a UID matching the
2482        // currently bound package name
2483
2484        if (isUidALocationProvider(Binder.getCallingUid())) {
2485            return;
2486        }
2487
2488        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2489                "or UID of a currently bound location provider");
2490    }
2491
2492    /**
2493     * Returns true if the given package belongs to the given uid.
2494     */
2495    private boolean doesUidHavePackage(int uid, String packageName) {
2496        if (packageName == null) {
2497            return false;
2498        }
2499        String[] packageNames = mPackageManager.getPackagesForUid(uid);
2500        if (packageNames == null) {
2501            return false;
2502        }
2503        for (String name : packageNames) {
2504            if (packageName.equals(name)) {
2505                return true;
2506            }
2507        }
2508        return false;
2509    }
2510
2511    @Override
2512    public void reportLocation(Location location, boolean passive) {
2513        checkCallerIsProvider();
2514
2515        if (!location.isComplete()) {
2516            Log.w(TAG, "Dropping incomplete location: " + location);
2517            return;
2518        }
2519
2520        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2521        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
2522        m.arg1 = (passive ? 1 : 0);
2523        mLocationHandler.sendMessageAtFrontOfQueue(m);
2524    }
2525
2526
2527    private static boolean shouldBroadcastSafe(
2528            Location loc, Location lastLoc, UpdateRecord record, long now) {
2529        // Always broadcast the first update
2530        if (lastLoc == null) {
2531            return true;
2532        }
2533
2534        // Check whether sufficient time has passed
2535        long minTime = record.mRequest.getFastestInterval();
2536        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2537                / NANOS_PER_MILLI;
2538        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
2539            return false;
2540        }
2541
2542        // Check whether sufficient distance has been traveled
2543        double minDistance = record.mRequest.getSmallestDisplacement();
2544        if (minDistance > 0.0) {
2545            if (loc.distanceTo(lastLoc) <= minDistance) {
2546                return false;
2547            }
2548        }
2549
2550        // Check whether sufficient number of udpates is left
2551        if (record.mRequest.getNumUpdates() <= 0) {
2552            return false;
2553        }
2554
2555        // Check whether the expiry date has passed
2556        return record.mRequest.getExpireAt() >= now;
2557    }
2558
2559    private void handleLocationChangedLocked(Location location, boolean passive) {
2560        if (D) Log.d(TAG, "incoming location: " + location);
2561
2562        long now = SystemClock.elapsedRealtime();
2563        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
2564
2565        // Skip if the provider is unknown.
2566        LocationProviderInterface p = mProvidersByName.get(provider);
2567        if (p == null) return;
2568
2569        // Update last known locations
2570        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2571        Location lastNoGPSLocation;
2572        Location lastLocation = mLastLocation.get(provider);
2573        if (lastLocation == null) {
2574            lastLocation = new Location(provider);
2575            mLastLocation.put(provider, lastLocation);
2576        } else {
2577            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2578            if (noGPSLocation == null && lastNoGPSLocation != null) {
2579                // New location has no no-GPS location: adopt last no-GPS location. This is set
2580                // directly into location because we do not want to notify COARSE clients.
2581                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2582            }
2583        }
2584        lastLocation.set(location);
2585
2586        // Update last known coarse interval location if enough time has passed.
2587        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2588        if (lastLocationCoarseInterval == null) {
2589            lastLocationCoarseInterval = new Location(location);
2590            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2591        }
2592        long timeDiffNanos = location.getElapsedRealtimeNanos()
2593                - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2594        if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2595            lastLocationCoarseInterval.set(location);
2596        }
2597        // Don't ever return a coarse location that is more recent than the allowed update
2598        // interval (i.e. don't allow an app to keep registering and unregistering for
2599        // location updates to overcome the minimum interval).
2600        noGPSLocation =
2601                lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2602
2603        // Skip if there are no UpdateRecords for this provider.
2604        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2605        if (records == null || records.size() == 0) return;
2606
2607        // Fetch coarse location
2608        Location coarseLocation = null;
2609        if (noGPSLocation != null) {
2610            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2611        }
2612
2613        // Fetch latest status update time
2614        long newStatusUpdateTime = p.getStatusUpdateTime();
2615
2616        // Get latest status
2617        Bundle extras = new Bundle();
2618        int status = p.getStatus(extras);
2619
2620        ArrayList<Receiver> deadReceivers = null;
2621        ArrayList<UpdateRecord> deadUpdateRecords = null;
2622
2623        // Broadcast location or status to all listeners
2624        for (UpdateRecord r : records) {
2625            Receiver receiver = r.mReceiver;
2626            boolean receiverDead = false;
2627
2628            int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
2629            if (!isCurrentProfile(receiverUserId)
2630                    && !isUidALocationProvider(receiver.mIdentity.mUid)) {
2631                if (D) {
2632                    Log.d(TAG, "skipping loc update for background user " + receiverUserId +
2633                            " (current user: " + mCurrentUserId + ", app: " +
2634                            receiver.mIdentity.mPackageName + ")");
2635                }
2636                continue;
2637            }
2638
2639            if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
2640                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2641                        receiver.mIdentity.mPackageName);
2642                continue;
2643            }
2644
2645            if (!reportLocationAccessNoThrow(
2646                    receiver.mIdentity.mPid,
2647                    receiver.mIdentity.mUid,
2648                    receiver.mIdentity.mPackageName,
2649                    receiver.mAllowedResolutionLevel)) {
2650                if (D) Log.d(TAG, "skipping loc update for no op app: " +
2651                        receiver.mIdentity.mPackageName);
2652                continue;
2653            }
2654
2655            Location notifyLocation;
2656            if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2657                notifyLocation = coarseLocation;  // use coarse location
2658            } else {
2659                notifyLocation = lastLocation;  // use fine location
2660            }
2661            if (notifyLocation != null) {
2662                Location lastLoc = r.mLastFixBroadcast;
2663                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
2664                    if (lastLoc == null) {
2665                        lastLoc = new Location(notifyLocation);
2666                        r.mLastFixBroadcast = lastLoc;
2667                    } else {
2668                        lastLoc.set(notifyLocation);
2669                    }
2670                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
2671                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2672                        receiverDead = true;
2673                    }
2674                    r.mRequest.decrementNumUpdates();
2675                }
2676            }
2677
2678            long prevStatusUpdateTime = r.mLastStatusBroadcast;
2679            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
2680                    (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
2681
2682                r.mLastStatusBroadcast = newStatusUpdateTime;
2683                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
2684                    receiverDead = true;
2685                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
2686                }
2687            }
2688
2689            // track expired records
2690            if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
2691                if (deadUpdateRecords == null) {
2692                    deadUpdateRecords = new ArrayList<>();
2693                }
2694                deadUpdateRecords.add(r);
2695            }
2696            // track dead receivers
2697            if (receiverDead) {
2698                if (deadReceivers == null) {
2699                    deadReceivers = new ArrayList<>();
2700                }
2701                if (!deadReceivers.contains(receiver)) {
2702                    deadReceivers.add(receiver);
2703                }
2704            }
2705        }
2706
2707        // remove dead records and receivers outside the loop
2708        if (deadReceivers != null) {
2709            for (Receiver receiver : deadReceivers) {
2710                removeUpdatesLocked(receiver);
2711            }
2712        }
2713        if (deadUpdateRecords != null) {
2714            for (UpdateRecord r : deadUpdateRecords) {
2715                r.disposeLocked(true);
2716            }
2717            applyRequirementsLocked(provider);
2718        }
2719    }
2720
2721    private class LocationWorkerHandler extends Handler {
2722        public LocationWorkerHandler(Looper looper) {
2723            super(looper, null, true);
2724        }
2725
2726        @Override
2727        public void handleMessage(Message msg) {
2728            switch (msg.what) {
2729                case MSG_LOCATION_CHANGED:
2730                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2731                    break;
2732            }
2733        }
2734    }
2735
2736    private boolean isMockProvider(String provider) {
2737        synchronized (mLock) {
2738            return mMockProviders.containsKey(provider);
2739        }
2740    }
2741
2742    private void handleLocationChanged(Location location, boolean passive) {
2743        // create a working copy of the incoming Location so that the service can modify it without
2744        // disturbing the caller's copy
2745        Location myLocation = new Location(location);
2746        String provider = myLocation.getProvider();
2747
2748        // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2749        // bit if location did not come from a mock provider because passive/fused providers can
2750        // forward locations from mock providers, and should not grant them legitimacy in doing so.
2751        if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2752            myLocation.setIsFromMockProvider(true);
2753        }
2754
2755        synchronized (mLock) {
2756            if (isAllowedByCurrentUserSettingsLocked(provider)) {
2757                if (!passive) {
2758                    // notify passive provider of the new location
2759                    mPassiveProvider.updateLocation(myLocation);
2760                }
2761                handleLocationChangedLocked(myLocation, passive);
2762            }
2763        }
2764    }
2765
2766    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2767        @Override
2768        public void onPackageDisappeared(String packageName, int reason) {
2769            // remove all receivers associated with this package name
2770            synchronized (mLock) {
2771                ArrayList<Receiver> deadReceivers = null;
2772
2773                for (Receiver receiver : mReceivers.values()) {
2774                    if (receiver.mIdentity.mPackageName.equals(packageName)) {
2775                        if (deadReceivers == null) {
2776                            deadReceivers = new ArrayList<>();
2777                        }
2778                        deadReceivers.add(receiver);
2779                    }
2780                }
2781
2782                // perform removal outside of mReceivers loop
2783                if (deadReceivers != null) {
2784                    for (Receiver receiver : deadReceivers) {
2785                        removeUpdatesLocked(receiver);
2786                    }
2787                }
2788            }
2789        }
2790    };
2791
2792    // Geocoder
2793
2794    @Override
2795    public boolean geocoderIsPresent() {
2796        return mGeocodeProvider != null;
2797    }
2798
2799    @Override
2800    public String getFromLocation(double latitude, double longitude, int maxResults,
2801            GeocoderParams params, List<Address> addrs) {
2802        if (mGeocodeProvider != null) {
2803            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2804                    params, addrs);
2805        }
2806        return null;
2807    }
2808
2809
2810    @Override
2811    public String getFromLocationName(String locationName,
2812            double lowerLeftLatitude, double lowerLeftLongitude,
2813            double upperRightLatitude, double upperRightLongitude, int maxResults,
2814            GeocoderParams params, List<Address> addrs) {
2815
2816        if (mGeocodeProvider != null) {
2817            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2818                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2819                    maxResults, params, addrs);
2820        }
2821        return null;
2822    }
2823
2824    // Mock Providers
2825
2826    private boolean canCallerAccessMockLocation(String opPackageName) {
2827        return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
2828                opPackageName) == AppOpsManager.MODE_ALLOWED;
2829    }
2830
2831    @Override
2832    public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
2833        if (!canCallerAccessMockLocation(opPackageName)) {
2834            return;
2835        }
2836
2837        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2838            throw new IllegalArgumentException("Cannot mock the passive location provider");
2839        }
2840
2841        long identity = Binder.clearCallingIdentity();
2842        synchronized (mLock) {
2843            // remove the real provider if we are replacing GPS or network provider
2844            if (LocationManager.GPS_PROVIDER.equals(name)
2845                    || LocationManager.NETWORK_PROVIDER.equals(name)
2846                    || LocationManager.FUSED_PROVIDER.equals(name)) {
2847                LocationProviderInterface p = mProvidersByName.get(name);
2848                if (p != null) {
2849                    removeProviderLocked(p);
2850                }
2851            }
2852            addTestProviderLocked(name, properties);
2853            updateProvidersLocked();
2854        }
2855        Binder.restoreCallingIdentity(identity);
2856    }
2857
2858    private void addTestProviderLocked(String name, ProviderProperties properties) {
2859        if (mProvidersByName.get(name) != null) {
2860            throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2861        }
2862        MockProvider provider = new MockProvider(name, this, properties);
2863        addProviderLocked(provider);
2864        mMockProviders.put(name, provider);
2865        mLastLocation.put(name, null);
2866        mLastLocationCoarseInterval.put(name, null);
2867    }
2868
2869    @Override
2870    public void removeTestProvider(String provider, String opPackageName) {
2871        if (!canCallerAccessMockLocation(opPackageName)) {
2872            return;
2873        }
2874
2875        synchronized (mLock) {
2876
2877            // These methods can't be called after removing the test provider, so first make sure
2878            // we don't leave anything dangling.
2879            clearTestProviderEnabled(provider, opPackageName);
2880            clearTestProviderLocation(provider, opPackageName);
2881            clearTestProviderStatus(provider, opPackageName);
2882
2883            MockProvider mockProvider = mMockProviders.remove(provider);
2884            if (mockProvider == null) {
2885                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2886            }
2887            long identity = Binder.clearCallingIdentity();
2888            removeProviderLocked(mProvidersByName.get(provider));
2889
2890            // reinstate real provider if available
2891            LocationProviderInterface realProvider = mRealProviders.get(provider);
2892            if (realProvider != null) {
2893                addProviderLocked(realProvider);
2894            }
2895            mLastLocation.put(provider, null);
2896            mLastLocationCoarseInterval.put(provider, null);
2897            updateProvidersLocked();
2898            Binder.restoreCallingIdentity(identity);
2899        }
2900    }
2901
2902    @Override
2903    public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
2904        if (!canCallerAccessMockLocation(opPackageName)) {
2905            return;
2906        }
2907
2908        synchronized (mLock) {
2909            MockProvider mockProvider = mMockProviders.get(provider);
2910            if (mockProvider == null) {
2911                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2912            }
2913
2914            // Ensure that the location is marked as being mock. There's some logic to do this in
2915            // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
2916            Location mock = new Location(loc);
2917            mock.setIsFromMockProvider(true);
2918
2919            if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
2920                // The location has an explicit provider that is different from the mock provider
2921                // name. The caller may be trying to fool us via bug 33091107.
2922                EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
2923                        provider + "!=" + loc.getProvider());
2924            }
2925
2926            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2927            long identity = Binder.clearCallingIdentity();
2928            mockProvider.setLocation(mock);
2929            Binder.restoreCallingIdentity(identity);
2930        }
2931    }
2932
2933    @Override
2934    public void clearTestProviderLocation(String provider, String opPackageName) {
2935        if (!canCallerAccessMockLocation(opPackageName)) {
2936            return;
2937        }
2938
2939        synchronized (mLock) {
2940            MockProvider mockProvider = mMockProviders.get(provider);
2941            if (mockProvider == null) {
2942                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2943            }
2944            mockProvider.clearLocation();
2945        }
2946    }
2947
2948    @Override
2949    public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
2950        if (!canCallerAccessMockLocation(opPackageName)) {
2951            return;
2952        }
2953
2954        synchronized (mLock) {
2955            MockProvider mockProvider = mMockProviders.get(provider);
2956            if (mockProvider == null) {
2957                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2958            }
2959            long identity = Binder.clearCallingIdentity();
2960            if (enabled) {
2961                mockProvider.enable();
2962                mEnabledProviders.add(provider);
2963                mDisabledProviders.remove(provider);
2964            } else {
2965                mockProvider.disable();
2966                mEnabledProviders.remove(provider);
2967                mDisabledProviders.add(provider);
2968            }
2969            updateProvidersLocked();
2970            Binder.restoreCallingIdentity(identity);
2971        }
2972    }
2973
2974    @Override
2975    public void clearTestProviderEnabled(String provider, String opPackageName) {
2976        if (!canCallerAccessMockLocation(opPackageName)) {
2977            return;
2978        }
2979
2980        synchronized (mLock) {
2981            MockProvider mockProvider = mMockProviders.get(provider);
2982            if (mockProvider == null) {
2983                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2984            }
2985            long identity = Binder.clearCallingIdentity();
2986            mEnabledProviders.remove(provider);
2987            mDisabledProviders.remove(provider);
2988            updateProvidersLocked();
2989            Binder.restoreCallingIdentity(identity);
2990        }
2991    }
2992
2993    @Override
2994    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
2995            String opPackageName) {
2996        if (!canCallerAccessMockLocation(opPackageName)) {
2997            return;
2998        }
2999
3000        synchronized (mLock) {
3001            MockProvider mockProvider = mMockProviders.get(provider);
3002            if (mockProvider == null) {
3003                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3004            }
3005            mockProvider.setStatus(status, extras, updateTime);
3006        }
3007    }
3008
3009    @Override
3010    public void clearTestProviderStatus(String provider, String opPackageName) {
3011        if (!canCallerAccessMockLocation(opPackageName)) {
3012            return;
3013        }
3014
3015        synchronized (mLock) {
3016            MockProvider mockProvider = mMockProviders.get(provider);
3017            if (mockProvider == null) {
3018                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3019            }
3020            mockProvider.clearStatus();
3021        }
3022    }
3023
3024    private void log(String log) {
3025        if (Log.isLoggable(TAG, Log.VERBOSE)) {
3026            Slog.d(TAG, log);
3027        }
3028    }
3029
3030    @Override
3031    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3032        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
3033
3034        synchronized (mLock) {
3035            if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3036                if (mGnssMetricsProvider != null) {
3037                    pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3038                }
3039                return;
3040            }
3041            pw.println("Current Location Manager state:");
3042            pw.println("  Location Listeners:");
3043            for (Receiver receiver : mReceivers.values()) {
3044                pw.println("    " + receiver);
3045            }
3046            pw.println("  Active Records by Provider:");
3047            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3048                pw.println("    " + entry.getKey() + ":");
3049                for (UpdateRecord record : entry.getValue()) {
3050                    pw.println("      " + record);
3051                }
3052            }
3053            pw.println("  Overlay Provider Packages:");
3054            for (LocationProviderInterface provider : mProviders) {
3055                if (provider instanceof LocationProviderProxy) {
3056                    pw.println("    " + provider.getName() + ": "
3057                            + ((LocationProviderProxy) provider).getConnectedPackageName());
3058                }
3059            }
3060            pw.println("  Historical Records by Provider:");
3061            for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3062                    : mRequestStatistics.statistics.entrySet()) {
3063                PackageProviderKey key = entry.getKey();
3064                PackageStatistics stats = entry.getValue();
3065                pw.println("    " + key.packageName + ": " + key.providerName + ": " + stats);
3066            }
3067            pw.println("  Last Known Locations:");
3068            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3069                String provider = entry.getKey();
3070                Location location = entry.getValue();
3071                pw.println("    " + provider + ": " + location);
3072            }
3073
3074            pw.println("  Last Known Locations Coarse Intervals:");
3075            for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3076                String provider = entry.getKey();
3077                Location location = entry.getValue();
3078                pw.println("    " + provider + ": " + location);
3079            }
3080
3081            mGeofenceManager.dump(pw);
3082
3083            if (mEnabledProviders.size() > 0) {
3084                pw.println("  Enabled Providers:");
3085                for (String i : mEnabledProviders) {
3086                    pw.println("    " + i);
3087                }
3088
3089            }
3090            if (mDisabledProviders.size() > 0) {
3091                pw.println("  Disabled Providers:");
3092                for (String i : mDisabledProviders) {
3093                    pw.println("    " + i);
3094                }
3095            }
3096            pw.append("  ");
3097            mBlacklist.dump(pw);
3098            if (mMockProviders.size() > 0) {
3099                pw.println("  Mock Providers:");
3100                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
3101                    i.getValue().dump(pw, "      ");
3102                }
3103            }
3104
3105            if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3106                pw.println("  Throttling Whitelisted Packages:");
3107                for (String packageName : mBackgroundThrottlePackageWhitelist) {
3108                    pw.println("    " + packageName);
3109                }
3110            }
3111
3112            pw.append("  fudger: ");
3113            mLocationFudger.dump(fd, pw,  args);
3114
3115            if (args.length > 0 && "short".equals(args[0])) {
3116                return;
3117            }
3118            for (LocationProviderInterface provider: mProviders) {
3119                pw.print(provider.getName() + " Internal State");
3120                if (provider instanceof LocationProviderProxy) {
3121                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
3122                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
3123                }
3124                pw.println(":");
3125                provider.dump(fd, pw, args);
3126            }
3127            if (mGnssBatchingInProgress) {
3128                pw.println("  GNSS batching in progress");
3129            }
3130        }
3131    }
3132}
3133