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