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