LocationManagerService.java revision 7a222661b523c6a51ac61b9f939eb594776c6307
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.ActivityManager;
20import android.annotation.NonNull;
21import android.util.ArrayMap;
22import android.util.ArraySet;
23import com.android.internal.content.PackageMonitor;
24import com.android.internal.location.ProviderProperties;
25import com.android.internal.location.ProviderRequest;
26import com.android.internal.os.BackgroundThread;
27import com.android.internal.util.ArrayUtils;
28import com.android.internal.util.DumpUtils;
29import com.android.server.location.ActivityRecognitionProxy;
30import com.android.server.location.FlpHardwareProvider;
31import com.android.server.location.FusedProxy;
32import com.android.server.location.GeocoderProxy;
33import com.android.server.location.GeofenceManager;
34import com.android.server.location.GeofenceProxy;
35import com.android.server.location.GnssLocationProvider;
36import com.android.server.location.GnssMeasurementsProvider;
37import com.android.server.location.GnssNavigationMessageProvider;
38import com.android.server.location.LocationBlacklist;
39import com.android.server.location.LocationFudger;
40import com.android.server.location.LocationProviderInterface;
41import com.android.server.location.LocationProviderProxy;
42import com.android.server.location.LocationRequestStatistics;
43import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
44import com.android.server.location.LocationRequestStatistics.PackageStatistics;
45import com.android.server.location.MockProvider;
46import com.android.server.location.PassiveProvider;
47
48import android.app.AppOpsManager;
49import android.app.PendingIntent;
50import android.content.BroadcastReceiver;
51import android.content.ContentResolver;
52import android.content.Context;
53import android.content.Intent;
54import android.content.IntentFilter;
55import android.content.pm.ApplicationInfo;
56import android.content.pm.PackageInfo;
57import android.content.pm.PackageManager;
58import android.content.pm.PackageManagerInternal;
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 = "*location*";
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        List<String> out = getProviders(null /*criteria*/, false /*enabledOnly*/);
1546        if (D) Log.d(TAG, "getAllProviders()=" + out);
1547        return out;
1548    }
1549
1550    /**
1551     * Return all providers by name, that match criteria and are optionally
1552     * enabled.
1553     * Can return passive provider, but never returns fused provider.
1554     */
1555    @Override
1556    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
1557        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1558        ArrayList<String> out;
1559        int uid = Binder.getCallingUid();
1560        long identity = Binder.clearCallingIdentity();
1561        try {
1562            synchronized (mLock) {
1563                out = new ArrayList<>(mProviders.size());
1564                for (LocationProviderInterface provider : mProviders) {
1565                    String name = provider.getName();
1566                    if (LocationManager.FUSED_PROVIDER.equals(name)) {
1567                        continue;
1568                    }
1569                    if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
1570                        if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
1571                            continue;
1572                        }
1573                        if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1574                                name, provider.getProperties(), criteria)) {
1575                            continue;
1576                        }
1577                        out.add(name);
1578                    }
1579                }
1580            }
1581        } finally {
1582            Binder.restoreCallingIdentity(identity);
1583        }
1584
1585        if (D) Log.d(TAG, "getProviders()=" + out);
1586        return out;
1587    }
1588
1589    /**
1590     * Return the name of the best provider given a Criteria object.
1591     * This method has been deprecated from the public API,
1592     * and the whole LocationProvider (including #meetsCriteria)
1593     * has been deprecated as well. So this method now uses
1594     * some simplified logic.
1595     */
1596    @Override
1597    public String getBestProvider(Criteria criteria, boolean enabledOnly) {
1598        String result = null;
1599
1600        List<String> providers = getProviders(criteria, enabledOnly);
1601        if (!providers.isEmpty()) {
1602            result = pickBest(providers);
1603            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1604            return result;
1605        }
1606        providers = getProviders(null, enabledOnly);
1607        if (!providers.isEmpty()) {
1608            result = pickBest(providers);
1609            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1610            return result;
1611        }
1612
1613        if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1614        return null;
1615    }
1616
1617    private String pickBest(List<String> providers) {
1618        if (providers.contains(LocationManager.GPS_PROVIDER)) {
1619            return LocationManager.GPS_PROVIDER;
1620        } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1621            return LocationManager.NETWORK_PROVIDER;
1622        } else {
1623            return providers.get(0);
1624        }
1625    }
1626
1627    @Override
1628    public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1629        LocationProviderInterface p = mProvidersByName.get(provider);
1630        if (p == null) {
1631            throw new IllegalArgumentException("provider=" + provider);
1632        }
1633
1634        boolean result = LocationProvider.propertiesMeetCriteria(
1635                p.getName(), p.getProperties(), criteria);
1636        if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1637        return result;
1638    }
1639
1640    private void updateProvidersLocked() {
1641        boolean changesMade = false;
1642        for (int i = mProviders.size() - 1; i >= 0; i--) {
1643            LocationProviderInterface p = mProviders.get(i);
1644            boolean isEnabled = p.isEnabled();
1645            String name = p.getName();
1646            boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
1647            if (isEnabled && !shouldBeEnabled) {
1648                updateProviderListenersLocked(name, false);
1649                // If any provider has been disabled, clear all last locations for all providers.
1650                // This is to be on the safe side in case a provider has location derived from
1651                // this disabled provider.
1652                mLastLocation.clear();
1653                mLastLocationCoarseInterval.clear();
1654                changesMade = true;
1655            } else if (!isEnabled && shouldBeEnabled) {
1656                updateProviderListenersLocked(name, true);
1657                changesMade = true;
1658            }
1659        }
1660        if (changesMade) {
1661            mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1662                    UserHandle.ALL);
1663            mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1664                    UserHandle.ALL);
1665        }
1666    }
1667
1668    private void updateProviderListenersLocked(String provider, boolean enabled) {
1669        int listeners = 0;
1670
1671        LocationProviderInterface p = mProvidersByName.get(provider);
1672        if (p == null) return;
1673
1674        ArrayList<Receiver> deadReceivers = null;
1675
1676        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1677        if (records != null) {
1678            for (UpdateRecord record : records) {
1679                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
1680                    // Sends a notification message to the receiver
1681                    if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1682                        if (deadReceivers == null) {
1683                            deadReceivers = new ArrayList<>();
1684                        }
1685                        deadReceivers.add(record.mReceiver);
1686                    }
1687                    listeners++;
1688                }
1689            }
1690        }
1691
1692        if (deadReceivers != null) {
1693            for (int i = deadReceivers.size() - 1; i >= 0; i--) {
1694                removeUpdatesLocked(deadReceivers.get(i));
1695            }
1696        }
1697
1698        if (enabled) {
1699            p.enable();
1700            if (listeners > 0) {
1701                applyRequirementsLocked(provider);
1702            }
1703        } else {
1704            p.disable();
1705        }
1706    }
1707
1708    private void applyRequirementsLocked(String provider) {
1709        LocationProviderInterface p = mProvidersByName.get(provider);
1710        if (p == null) return;
1711
1712        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1713        WorkSource worksource = new WorkSource();
1714        ProviderRequest providerRequest = new ProviderRequest();
1715
1716        ContentResolver resolver = mContext.getContentResolver();
1717        long backgroundThrottleInterval = Settings.Global.getLong(
1718                resolver,
1719                Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1720                DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
1721
1722        if (records != null) {
1723            for (UpdateRecord record : records) {
1724                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
1725                    if (checkLocationAccess(
1726                            record.mReceiver.mIdentity.mPid,
1727                            record.mReceiver.mIdentity.mUid,
1728                            record.mReceiver.mIdentity.mPackageName,
1729                            record.mReceiver.mAllowedResolutionLevel)) {
1730                        LocationRequest locationRequest = record.mRealRequest;
1731                        long interval = locationRequest.getInterval();
1732
1733                        if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
1734                            if (!record.mIsForegroundUid) {
1735                                interval = Math.max(interval, backgroundThrottleInterval);
1736                            }
1737                            if (interval != locationRequest.getInterval()) {
1738                                locationRequest = new LocationRequest(locationRequest);
1739                                locationRequest.setInterval(interval);
1740                            }
1741                        }
1742
1743                        record.mRequest = locationRequest;
1744                        providerRequest.locationRequests.add(locationRequest);
1745                        if (interval < providerRequest.interval) {
1746                            providerRequest.reportLocation = true;
1747                            providerRequest.interval = interval;
1748                        }
1749                    }
1750                }
1751            }
1752
1753            if (providerRequest.reportLocation) {
1754                // calculate who to blame for power
1755                // This is somewhat arbitrary. We pick a threshold interval
1756                // that is slightly higher that the minimum interval, and
1757                // spread the blame across all applications with a request
1758                // under that threshold.
1759                long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1760                for (UpdateRecord record : records) {
1761                    if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
1762                        LocationRequest locationRequest = record.mRequest;
1763
1764                        // Don't assign battery blame for update records whose
1765                        // client has no permission to receive location data.
1766                        if (!providerRequest.locationRequests.contains(locationRequest)) {
1767                            continue;
1768                        }
1769
1770                        if (locationRequest.getInterval() <= thresholdInterval) {
1771                            if (record.mReceiver.mWorkSource != null
1772                                    && record.mReceiver.mWorkSource.size() > 0
1773                                    && record.mReceiver.mWorkSource.getName(0) != null) {
1774                                // Assign blame to another work source.
1775                                // Can only assign blame if the WorkSource contains names.
1776                                worksource.add(record.mReceiver.mWorkSource);
1777                            } else {
1778                                // Assign blame to caller.
1779                                worksource.add(
1780                                        record.mReceiver.mIdentity.mUid,
1781                                        record.mReceiver.mIdentity.mPackageName);
1782                            }
1783                        }
1784                    }
1785                }
1786            }
1787        }
1788
1789        if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1790        p.setRequest(providerRequest, worksource);
1791    }
1792
1793    @Override
1794    public String[] getBackgroundThrottlingWhitelist() {
1795        synchronized (mLock) {
1796            return mBackgroundThrottlePackageWhitelist.toArray(
1797                new String[mBackgroundThrottlePackageWhitelist.size()]);
1798        }
1799    }
1800
1801    private void updateBackgroundThrottlingWhitelistLocked() {
1802        String setting = Settings.Global.getString(
1803            mContext.getContentResolver(),
1804            Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
1805        if (setting == null) {
1806            setting = "";
1807        }
1808
1809        mBackgroundThrottlePackageWhitelist.clear();
1810        mBackgroundThrottlePackageWhitelist.addAll(
1811            SystemConfig.getInstance().getAllowUnthrottledLocation());
1812        mBackgroundThrottlePackageWhitelist.addAll(
1813            Arrays.asList(setting.split(",")));
1814    }
1815
1816    private boolean isThrottlingExemptLocked(Identity identity) {
1817        if (identity.mUid == Process.SYSTEM_UID) {
1818            return true;
1819        }
1820
1821        if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
1822            return true;
1823        }
1824
1825        for (LocationProviderProxy provider : mProxyProviders) {
1826            if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
1827                return true;
1828            }
1829        }
1830
1831        return false;
1832    }
1833
1834    private class UpdateRecord {
1835        final String mProvider;
1836        final LocationRequest mRealRequest;  // original request from client
1837        LocationRequest mRequest;  // possibly throttled version of the request
1838        final Receiver mReceiver;
1839        boolean mIsForegroundUid;
1840        Location mLastFixBroadcast;
1841        long mLastStatusBroadcast;
1842
1843        /**
1844         * Note: must be constructed with lock held.
1845         */
1846        UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
1847            mProvider = provider;
1848            mRealRequest = request;
1849            mRequest = request;
1850            mReceiver = receiver;
1851            mIsForegroundUid = isImportanceForeground(
1852                    mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
1853
1854            ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1855            if (records == null) {
1856                records = new ArrayList<>();
1857                mRecordsByProvider.put(provider, records);
1858            }
1859            if (!records.contains(this)) {
1860                records.add(this);
1861            }
1862
1863            // Update statistics for historical location requests by package/provider
1864            mRequestStatistics.startRequesting(
1865                    mReceiver.mIdentity.mPackageName, provider, request.getInterval());
1866        }
1867
1868        /**
1869         * Method to be called when a record will no longer be used.
1870         */
1871        void disposeLocked(boolean removeReceiver) {
1872            mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
1873
1874            // remove from mRecordsByProvider
1875            ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1876            if (globalRecords != null) {
1877                globalRecords.remove(this);
1878            }
1879
1880            if (!removeReceiver) return;  // the caller will handle the rest
1881
1882            // remove from Receiver#mUpdateRecords
1883            HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1884            if (receiverRecords != null) {
1885                receiverRecords.remove(this.mProvider);
1886
1887                // and also remove the Receiver if it has no more update records
1888                if (receiverRecords.size() == 0) {
1889                    removeUpdatesLocked(mReceiver);
1890                }
1891            }
1892        }
1893
1894        @Override
1895        public String toString() {
1896            return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
1897                    + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground" : " background")
1898                    + ")" + " " + mRealRequest + "]";
1899        }
1900    }
1901
1902    private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
1903            String packageName, WorkSource workSource, boolean hideFromAppOps) {
1904        IBinder binder = listener.asBinder();
1905        Receiver receiver = mReceivers.get(binder);
1906        if (receiver == null) {
1907            receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1908                    hideFromAppOps);
1909            try {
1910                receiver.getListener().asBinder().linkToDeath(receiver, 0);
1911            } catch (RemoteException e) {
1912                Slog.e(TAG, "linkToDeath failed:", e);
1913                return null;
1914            }
1915            mReceivers.put(binder, receiver);
1916        }
1917        return receiver;
1918    }
1919
1920    private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
1921            WorkSource workSource, boolean hideFromAppOps) {
1922        Receiver receiver = mReceivers.get(intent);
1923        if (receiver == null) {
1924            receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1925                    hideFromAppOps);
1926            mReceivers.put(intent, receiver);
1927        }
1928        return receiver;
1929    }
1930
1931    /**
1932     * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1933     * and consistency requirements.
1934     *
1935     * @param request the LocationRequest from which to create a sanitized version
1936     * @return a version of request that meets the given resolution and consistency requirements
1937     * @hide
1938     */
1939    private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1940        LocationRequest sanitizedRequest = new LocationRequest(request);
1941        if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1942            switch (sanitizedRequest.getQuality()) {
1943                case LocationRequest.ACCURACY_FINE:
1944                    sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
1945                    break;
1946                case LocationRequest.POWER_HIGH:
1947                    sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
1948                    break;
1949            }
1950            // throttle
1951            if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1952                sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1953            }
1954            if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1955                sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1956            }
1957        }
1958        // make getFastestInterval() the minimum of interval and fastest interval
1959        if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
1960            request.setFastestInterval(request.getInterval());
1961        }
1962        return sanitizedRequest;
1963    }
1964
1965    private void checkPackageName(String packageName) {
1966        if (packageName == null) {
1967            throw new SecurityException("invalid package name: " + packageName);
1968        }
1969        int uid = Binder.getCallingUid();
1970        String[] packages = mPackageManager.getPackagesForUid(uid);
1971        if (packages == null) {
1972            throw new SecurityException("invalid UID " + uid);
1973        }
1974        for (String pkg : packages) {
1975            if (packageName.equals(pkg)) return;
1976        }
1977        throw new SecurityException("invalid package name: " + packageName);
1978    }
1979
1980    private void checkPendingIntent(PendingIntent intent) {
1981        if (intent == null) {
1982            throw new IllegalArgumentException("invalid pending intent: " + intent);
1983        }
1984    }
1985
1986    private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
1987            int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
1988        if (intent == null && listener == null) {
1989            throw new IllegalArgumentException("need either listener or intent");
1990        } else if (intent != null && listener != null) {
1991            throw new IllegalArgumentException("cannot register both listener and intent");
1992        } else if (intent != null) {
1993            checkPendingIntent(intent);
1994            return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
1995        } else {
1996            return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
1997        }
1998    }
1999
2000    @Override
2001    public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
2002            PendingIntent intent, String packageName) {
2003        if (request == null) request = DEFAULT_LOCATION_REQUEST;
2004        checkPackageName(packageName);
2005        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2006        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2007                request.getProvider());
2008        WorkSource workSource = request.getWorkSource();
2009        if (workSource != null && workSource.size() > 0) {
2010            checkDeviceStatsAllowed();
2011        }
2012        boolean hideFromAppOps = request.getHideFromAppOps();
2013        if (hideFromAppOps) {
2014            checkUpdateAppOpsAllowed();
2015        }
2016        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
2017
2018        final int pid = Binder.getCallingPid();
2019        final int uid = Binder.getCallingUid();
2020        // providers may use public location API's, need to clear identity
2021        long identity = Binder.clearCallingIdentity();
2022        try {
2023            // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2024            // a location.
2025            checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
2026
2027            synchronized (mLock) {
2028                Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
2029                        packageName, workSource, hideFromAppOps);
2030                requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
2031            }
2032        } finally {
2033            Binder.restoreCallingIdentity(identity);
2034        }
2035    }
2036
2037    private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
2038            int pid, int uid, String packageName) {
2039        // Figure out the provider. Either its explicitly request (legacy use cases), or
2040        // use the fused provider
2041        if (request == null) request = DEFAULT_LOCATION_REQUEST;
2042        String name = request.getProvider();
2043        if (name == null) {
2044            throw new IllegalArgumentException("provider name must not be null");
2045        }
2046
2047        LocationProviderInterface provider = mProvidersByName.get(name);
2048        if (provider == null) {
2049            throw new IllegalArgumentException("provider doesn't exist: " + name);
2050        }
2051
2052        UpdateRecord record = new UpdateRecord(name, request, receiver);
2053        if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2054                + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2055                + (record.mIsForegroundUid ? "foreground" : "background")
2056                + (isThrottlingExemptLocked(receiver.mIdentity)
2057                    ? " [whitelisted]" : "") + ")");
2058
2059        UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2060        if (oldRecord != null) {
2061            oldRecord.disposeLocked(false);
2062        }
2063
2064        boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
2065        if (isProviderEnabled) {
2066            applyRequirementsLocked(name);
2067        } else {
2068            // Notify the listener that updates are currently disabled
2069            receiver.callProviderEnabledLocked(name, false);
2070        }
2071        // Update the monitoring here just in case multiple location requests were added to the
2072        // same receiver (this request may be high power and the initial might not have been).
2073        receiver.updateMonitoring(true);
2074    }
2075
2076    @Override
2077    public void removeUpdates(ILocationListener listener, PendingIntent intent,
2078            String packageName) {
2079        checkPackageName(packageName);
2080
2081        final int pid = Binder.getCallingPid();
2082        final int uid = Binder.getCallingUid();
2083
2084        synchronized (mLock) {
2085            WorkSource workSource = null;
2086            boolean hideFromAppOps = false;
2087            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
2088                    packageName, workSource, hideFromAppOps);
2089
2090            // providers may use public location API's, need to clear identity
2091            long identity = Binder.clearCallingIdentity();
2092            try {
2093                removeUpdatesLocked(receiver);
2094            } finally {
2095                Binder.restoreCallingIdentity(identity);
2096            }
2097        }
2098    }
2099
2100    private void removeUpdatesLocked(Receiver receiver) {
2101        if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
2102
2103        if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2104            receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2105            synchronized (receiver) {
2106                receiver.clearPendingBroadcastsLocked();
2107            }
2108        }
2109
2110        receiver.updateMonitoring(false);
2111
2112        // Record which providers were associated with this listener
2113        HashSet<String> providers = new HashSet<>();
2114        HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2115        if (oldRecords != null) {
2116            // Call dispose() on the obsolete update records.
2117            for (UpdateRecord record : oldRecords.values()) {
2118                // Update statistics for historical location requests by package/provider
2119                record.disposeLocked(false);
2120            }
2121            // Accumulate providers
2122            providers.addAll(oldRecords.keySet());
2123        }
2124
2125        // update provider
2126        for (String provider : providers) {
2127            // If provider is already disabled, don't need to do anything
2128            if (!isAllowedByCurrentUserSettingsLocked(provider)) {
2129                continue;
2130            }
2131
2132            applyRequirementsLocked(provider);
2133        }
2134    }
2135
2136    private void applyAllProviderRequirementsLocked() {
2137        for (LocationProviderInterface p : mProviders) {
2138            // If provider is already disabled, don't need to do anything
2139            if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
2140                continue;
2141            }
2142
2143            applyRequirementsLocked(p.getName());
2144        }
2145    }
2146
2147    @Override
2148    public Location getLastLocation(LocationRequest request, String packageName) {
2149        if (D) Log.d(TAG, "getLastLocation: " + request);
2150        if (request == null) request = DEFAULT_LOCATION_REQUEST;
2151        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2152        checkPackageName(packageName);
2153        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2154                request.getProvider());
2155        // no need to sanitize this request, as only the provider name is used
2156
2157        final int pid = Binder.getCallingPid();
2158        final int uid = Binder.getCallingUid();
2159        final long identity = Binder.clearCallingIdentity();
2160        try {
2161            if (mBlacklist.isBlacklisted(packageName)) {
2162                if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
2163                        packageName);
2164                return null;
2165            }
2166
2167            if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
2168                if (D) Log.d(TAG, "not returning last loc for no op app: " +
2169                        packageName);
2170                return null;
2171            }
2172
2173            synchronized (mLock) {
2174                // Figure out the provider. Either its explicitly request (deprecated API's),
2175                // or use the fused provider
2176                String name = request.getProvider();
2177                if (name == null) name = LocationManager.FUSED_PROVIDER;
2178                LocationProviderInterface provider = mProvidersByName.get(name);
2179                if (provider == null) return null;
2180
2181                if (!isAllowedByUserSettingsLocked(name, uid)) return null;
2182
2183                Location location;
2184                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2185                    // Make sure that an app with coarse permissions can't get frequent location
2186                    // updates by calling LocationManager.getLastKnownLocation repeatedly.
2187                    location = mLastLocationCoarseInterval.get(name);
2188                } else {
2189                    location = mLastLocation.get(name);
2190                }
2191                if (location == null) {
2192                    return null;
2193                }
2194                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2195                    Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2196                    if (noGPSLocation != null) {
2197                        return new Location(mLocationFudger.getOrCreate(noGPSLocation));
2198                    }
2199                } else {
2200                    return new Location(location);
2201                }
2202            }
2203            return null;
2204        } finally {
2205            Binder.restoreCallingIdentity(identity);
2206        }
2207    }
2208
2209    @Override
2210    public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2211            String packageName) {
2212        if (request == null) request = DEFAULT_LOCATION_REQUEST;
2213        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2214        checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
2215        checkPendingIntent(intent);
2216        checkPackageName(packageName);
2217        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2218                request.getProvider());
2219        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
2220
2221        if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
2222
2223        // geo-fence manager uses the public location API, need to clear identity
2224        int uid = Binder.getCallingUid();
2225        // TODO: http://b/23822629
2226        if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
2227            // temporary measure until geofences work for secondary users
2228            Log.w(TAG, "proximity alerts are currently available only to the primary user");
2229            return;
2230        }
2231        long identity = Binder.clearCallingIdentity();
2232        try {
2233            mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2234                    uid, packageName);
2235        } finally {
2236            Binder.restoreCallingIdentity(identity);
2237        }
2238    }
2239
2240    @Override
2241    public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
2242        checkPendingIntent(intent);
2243        checkPackageName(packageName);
2244
2245        if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2246
2247        // geo-fence manager uses the public location API, need to clear identity
2248        long identity = Binder.clearCallingIdentity();
2249        try {
2250            mGeofenceManager.removeFence(geofence, intent);
2251        } finally {
2252            Binder.restoreCallingIdentity(identity);
2253        }
2254    }
2255
2256
2257    @Override
2258    public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
2259        if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
2260            return false;
2261        }
2262
2263        try {
2264            mGnssStatusProvider.registerGnssStatusCallback(callback);
2265        } catch (RemoteException e) {
2266            Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
2267            return false;
2268        }
2269        return true;
2270    }
2271
2272    @Override
2273    public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
2274        synchronized (mLock) {
2275            try {
2276                mGnssStatusProvider.unregisterGnssStatusCallback(callback);
2277            } catch (Exception e) {
2278                Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
2279            }
2280        }
2281    }
2282
2283    @Override
2284    public boolean addGnssMeasurementsListener(
2285            IGnssMeasurementsListener listener,
2286            String packageName) {
2287        if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2288            return false;
2289        }
2290
2291        synchronized (mLock) {
2292            Identity callerIdentity
2293                    = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
2294            mGnssMeasurementsListeners.put(listener, callerIdentity);
2295            long identity = Binder.clearCallingIdentity();
2296            try {
2297                if (isThrottlingExemptLocked(callerIdentity)
2298                        || isImportanceForeground(
2299                                mActivityManager.getPackageImportance(packageName))) {
2300                    return mGnssMeasurementsProvider.addListener(listener);
2301                }
2302            } finally {
2303                Binder.restoreCallingIdentity(identity);
2304            }
2305
2306            return true;
2307        }
2308    }
2309
2310    @Override
2311    public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
2312        if (mGnssMeasurementsProvider != null) {
2313            synchronized (mLock) {
2314                mGnssMeasurementsListeners.remove(listener);
2315                mGnssMeasurementsProvider.removeListener(listener);
2316            }
2317        }
2318    }
2319
2320    @Override
2321    public boolean addGnssNavigationMessageListener(
2322            IGnssNavigationMessageListener listener,
2323            String packageName) {
2324        if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
2325            return false;
2326        }
2327
2328        synchronized (mLock) {
2329            Identity callerIdentity
2330                = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
2331            mGnssNavigationMessageListeners.put(listener, callerIdentity);
2332            long identity = Binder.clearCallingIdentity();
2333            try {
2334                if (isThrottlingExemptLocked(callerIdentity)
2335                        || isImportanceForeground(
2336                                mActivityManager.getPackageImportance(packageName))) {
2337                    return mGnssNavigationMessageProvider.addListener(listener);
2338                }
2339            } finally {
2340                Binder.restoreCallingIdentity(identity);
2341            }
2342
2343            return true;
2344        }
2345    }
2346
2347    @Override
2348    public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2349        if (mGnssNavigationMessageProvider != null) {
2350            synchronized (mLock) {
2351                mGnssNavigationMessageListeners.remove(listener);
2352                mGnssNavigationMessageProvider.removeListener(listener);
2353            }
2354        }
2355    }
2356
2357    @Override
2358    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
2359        if (provider == null) {
2360            // throw NullPointerException to remain compatible with previous implementation
2361            throw new NullPointerException();
2362        }
2363        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2364                provider);
2365
2366        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
2367        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
2368                != PackageManager.PERMISSION_GRANTED)) {
2369            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2370        }
2371
2372        synchronized (mLock) {
2373            LocationProviderInterface p = mProvidersByName.get(provider);
2374            if (p == null) return false;
2375
2376            return p.sendExtraCommand(command, extras);
2377        }
2378    }
2379
2380    @Override
2381    public boolean sendNiResponse(int notifId, int userResponse) {
2382        if (Binder.getCallingUid() != Process.myUid()) {
2383            throw new SecurityException(
2384                    "calling sendNiResponse from outside of the system is not allowed");
2385        }
2386        try {
2387            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
2388        } catch (RemoteException e) {
2389            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
2390            return false;
2391        }
2392    }
2393
2394    /**
2395     * @return null if the provider does not exist
2396     * @throws SecurityException if the provider is not allowed to be
2397     * accessed by the caller
2398     */
2399    @Override
2400    public ProviderProperties getProviderProperties(String provider) {
2401        if (mProvidersByName.get(provider) == null) {
2402            return null;
2403        }
2404
2405        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2406                provider);
2407
2408        LocationProviderInterface p;
2409        synchronized (mLock) {
2410            p = mProvidersByName.get(provider);
2411        }
2412
2413        if (p == null) return null;
2414        return p.getProperties();
2415    }
2416
2417    /**
2418     * @return null if the provider does not exist
2419     * @throws SecurityException if the provider is not allowed to be
2420     * accessed by the caller
2421     */
2422    @Override
2423    public String getNetworkProviderPackage() {
2424        LocationProviderInterface p;
2425        synchronized (mLock) {
2426            if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2427                return null;
2428            }
2429            p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2430        }
2431
2432        if (p instanceof LocationProviderProxy) {
2433            return ((LocationProviderProxy) p).getConnectedPackageName();
2434        }
2435        return null;
2436    }
2437
2438    @Override
2439    public boolean isProviderEnabled(String provider) {
2440        // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2441        // so we discourage its use
2442        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2443
2444        int uid = Binder.getCallingUid();
2445        long identity = Binder.clearCallingIdentity();
2446        try {
2447            synchronized (mLock) {
2448                LocationProviderInterface p = mProvidersByName.get(provider);
2449                return p != null && isAllowedByUserSettingsLocked(provider, uid);
2450            }
2451        } finally {
2452            Binder.restoreCallingIdentity(identity);
2453        }
2454    }
2455
2456    /**
2457     * Returns "true" if the UID belongs to a bound location provider.
2458     *
2459     * @param uid the uid
2460     * @return true if uid belongs to a bound location provider
2461     */
2462    private boolean isUidALocationProvider(int uid) {
2463        if (uid == Process.SYSTEM_UID) {
2464            return true;
2465        }
2466        if (mGeocodeProvider != null) {
2467            if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
2468        }
2469        for (LocationProviderProxy proxy : mProxyProviders) {
2470            if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
2471        }
2472        return false;
2473    }
2474
2475    private void checkCallerIsProvider() {
2476        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2477                == PackageManager.PERMISSION_GRANTED) {
2478            return;
2479        }
2480
2481        // Previously we only used the INSTALL_LOCATION_PROVIDER
2482        // check. But that is system or signature
2483        // protection level which is not flexible enough for
2484        // providers installed oustide the system image. So
2485        // also allow providers with a UID matching the
2486        // currently bound package name
2487
2488        if (isUidALocationProvider(Binder.getCallingUid())) {
2489            return;
2490        }
2491
2492        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2493                "or UID of a currently bound location provider");
2494    }
2495
2496    /**
2497     * Returns true if the given package belongs to the given uid.
2498     */
2499    private boolean doesUidHavePackage(int uid, String packageName) {
2500        if (packageName == null) {
2501            return false;
2502        }
2503        String[] packageNames = mPackageManager.getPackagesForUid(uid);
2504        if (packageNames == null) {
2505            return false;
2506        }
2507        for (String name : packageNames) {
2508            if (packageName.equals(name)) {
2509                return true;
2510            }
2511        }
2512        return false;
2513    }
2514
2515    @Override
2516    public void reportLocation(Location location, boolean passive) {
2517        checkCallerIsProvider();
2518
2519        if (!location.isComplete()) {
2520            Log.w(TAG, "Dropping incomplete location: " + location);
2521            return;
2522        }
2523
2524        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2525        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
2526        m.arg1 = (passive ? 1 : 0);
2527        mLocationHandler.sendMessageAtFrontOfQueue(m);
2528    }
2529
2530
2531    private static boolean shouldBroadcastSafe(
2532            Location loc, Location lastLoc, UpdateRecord record, long now) {
2533        // Always broadcast the first update
2534        if (lastLoc == null) {
2535            return true;
2536        }
2537
2538        // Check whether sufficient time has passed
2539        long minTime = record.mRealRequest.getFastestInterval();
2540        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2541                / NANOS_PER_MILLI;
2542        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
2543            return false;
2544        }
2545
2546        // Check whether sufficient distance has been traveled
2547        double minDistance = record.mRealRequest.getSmallestDisplacement();
2548        if (minDistance > 0.0) {
2549            if (loc.distanceTo(lastLoc) <= minDistance) {
2550                return false;
2551            }
2552        }
2553
2554        // Check whether sufficient number of udpates is left
2555        if (record.mRealRequest.getNumUpdates() <= 0) {
2556            return false;
2557        }
2558
2559        // Check whether the expiry date has passed
2560        return record.mRealRequest.getExpireAt() >= now;
2561    }
2562
2563    private void handleLocationChangedLocked(Location location, boolean passive) {
2564        if (D) Log.d(TAG, "incoming location: " + location);
2565
2566        long now = SystemClock.elapsedRealtime();
2567        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
2568
2569        // Skip if the provider is unknown.
2570        LocationProviderInterface p = mProvidersByName.get(provider);
2571        if (p == null) return;
2572
2573        // Update last known locations
2574        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2575        Location lastNoGPSLocation;
2576        Location lastLocation = mLastLocation.get(provider);
2577        if (lastLocation == null) {
2578            lastLocation = new Location(provider);
2579            mLastLocation.put(provider, lastLocation);
2580        } else {
2581            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2582            if (noGPSLocation == null && lastNoGPSLocation != null) {
2583                // New location has no no-GPS location: adopt last no-GPS location. This is set
2584                // directly into location because we do not want to notify COARSE clients.
2585                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2586            }
2587        }
2588        lastLocation.set(location);
2589
2590        // Update last known coarse interval location if enough time has passed.
2591        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2592        if (lastLocationCoarseInterval == null) {
2593            lastLocationCoarseInterval = new Location(location);
2594            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2595        }
2596        long timeDiffNanos = location.getElapsedRealtimeNanos()
2597                - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2598        if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2599            lastLocationCoarseInterval.set(location);
2600        }
2601        // Don't ever return a coarse location that is more recent than the allowed update
2602        // interval (i.e. don't allow an app to keep registering and unregistering for
2603        // location updates to overcome the minimum interval).
2604        noGPSLocation =
2605                lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2606
2607        // Skip if there are no UpdateRecords for this provider.
2608        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2609        if (records == null || records.size() == 0) return;
2610
2611        // Fetch coarse location
2612        Location coarseLocation = null;
2613        if (noGPSLocation != null) {
2614            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2615        }
2616
2617        // Fetch latest status update time
2618        long newStatusUpdateTime = p.getStatusUpdateTime();
2619
2620        // Get latest status
2621        Bundle extras = new Bundle();
2622        int status = p.getStatus(extras);
2623
2624        ArrayList<Receiver> deadReceivers = null;
2625        ArrayList<UpdateRecord> deadUpdateRecords = null;
2626
2627        // Broadcast location or status to all listeners
2628        for (UpdateRecord r : records) {
2629            Receiver receiver = r.mReceiver;
2630            boolean receiverDead = false;
2631
2632            int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
2633            if (!isCurrentProfile(receiverUserId)
2634                    && !isUidALocationProvider(receiver.mIdentity.mUid)) {
2635                if (D) {
2636                    Log.d(TAG, "skipping loc update for background user " + receiverUserId +
2637                            " (current user: " + mCurrentUserId + ", app: " +
2638                            receiver.mIdentity.mPackageName + ")");
2639                }
2640                continue;
2641            }
2642
2643            if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
2644                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2645                        receiver.mIdentity.mPackageName);
2646                continue;
2647            }
2648
2649            if (!reportLocationAccessNoThrow(
2650                    receiver.mIdentity.mPid,
2651                    receiver.mIdentity.mUid,
2652                    receiver.mIdentity.mPackageName,
2653                    receiver.mAllowedResolutionLevel)) {
2654                if (D) Log.d(TAG, "skipping loc update for no op app: " +
2655                        receiver.mIdentity.mPackageName);
2656                continue;
2657            }
2658
2659            Location notifyLocation;
2660            if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2661                notifyLocation = coarseLocation;  // use coarse location
2662            } else {
2663                notifyLocation = lastLocation;  // use fine location
2664            }
2665            if (notifyLocation != null) {
2666                Location lastLoc = r.mLastFixBroadcast;
2667                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
2668                    if (lastLoc == null) {
2669                        lastLoc = new Location(notifyLocation);
2670                        r.mLastFixBroadcast = lastLoc;
2671                    } else {
2672                        lastLoc.set(notifyLocation);
2673                    }
2674                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
2675                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2676                        receiverDead = true;
2677                    }
2678                    r.mRealRequest.decrementNumUpdates();
2679                }
2680            }
2681
2682            long prevStatusUpdateTime = r.mLastStatusBroadcast;
2683            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
2684                    (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
2685
2686                r.mLastStatusBroadcast = newStatusUpdateTime;
2687                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
2688                    receiverDead = true;
2689                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
2690                }
2691            }
2692
2693            // track expired records
2694            if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
2695                if (deadUpdateRecords == null) {
2696                    deadUpdateRecords = new ArrayList<>();
2697                }
2698                deadUpdateRecords.add(r);
2699            }
2700            // track dead receivers
2701            if (receiverDead) {
2702                if (deadReceivers == null) {
2703                    deadReceivers = new ArrayList<>();
2704                }
2705                if (!deadReceivers.contains(receiver)) {
2706                    deadReceivers.add(receiver);
2707                }
2708            }
2709        }
2710
2711        // remove dead records and receivers outside the loop
2712        if (deadReceivers != null) {
2713            for (Receiver receiver : deadReceivers) {
2714                removeUpdatesLocked(receiver);
2715            }
2716        }
2717        if (deadUpdateRecords != null) {
2718            for (UpdateRecord r : deadUpdateRecords) {
2719                r.disposeLocked(true);
2720            }
2721            applyRequirementsLocked(provider);
2722        }
2723    }
2724
2725    private class LocationWorkerHandler extends Handler {
2726        public LocationWorkerHandler(Looper looper) {
2727            super(looper, null, true);
2728        }
2729
2730        @Override
2731        public void handleMessage(Message msg) {
2732            switch (msg.what) {
2733                case MSG_LOCATION_CHANGED:
2734                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2735                    break;
2736            }
2737        }
2738    }
2739
2740    private boolean isMockProvider(String provider) {
2741        synchronized (mLock) {
2742            return mMockProviders.containsKey(provider);
2743        }
2744    }
2745
2746    private void handleLocationChanged(Location location, boolean passive) {
2747        // create a working copy of the incoming Location so that the service can modify it without
2748        // disturbing the caller's copy
2749        Location myLocation = new Location(location);
2750        String provider = myLocation.getProvider();
2751
2752        // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2753        // bit if location did not come from a mock provider because passive/fused providers can
2754        // forward locations from mock providers, and should not grant them legitimacy in doing so.
2755        if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2756            myLocation.setIsFromMockProvider(true);
2757        }
2758
2759        synchronized (mLock) {
2760            if (isAllowedByCurrentUserSettingsLocked(provider)) {
2761                if (!passive) {
2762                    // notify passive provider of the new location
2763                    mPassiveProvider.updateLocation(myLocation);
2764                }
2765                handleLocationChangedLocked(myLocation, passive);
2766            }
2767        }
2768    }
2769
2770    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2771        @Override
2772        public void onPackageDisappeared(String packageName, int reason) {
2773            // remove all receivers associated with this package name
2774            synchronized (mLock) {
2775                ArrayList<Receiver> deadReceivers = null;
2776
2777                for (Receiver receiver : mReceivers.values()) {
2778                    if (receiver.mIdentity.mPackageName.equals(packageName)) {
2779                        if (deadReceivers == null) {
2780                            deadReceivers = new ArrayList<>();
2781                        }
2782                        deadReceivers.add(receiver);
2783                    }
2784                }
2785
2786                // perform removal outside of mReceivers loop
2787                if (deadReceivers != null) {
2788                    for (Receiver receiver : deadReceivers) {
2789                        removeUpdatesLocked(receiver);
2790                    }
2791                }
2792            }
2793        }
2794    };
2795
2796    // Geocoder
2797
2798    @Override
2799    public boolean geocoderIsPresent() {
2800        return mGeocodeProvider != null;
2801    }
2802
2803    @Override
2804    public String getFromLocation(double latitude, double longitude, int maxResults,
2805            GeocoderParams params, List<Address> addrs) {
2806        if (mGeocodeProvider != null) {
2807            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2808                    params, addrs);
2809        }
2810        return null;
2811    }
2812
2813
2814    @Override
2815    public String getFromLocationName(String locationName,
2816            double lowerLeftLatitude, double lowerLeftLongitude,
2817            double upperRightLatitude, double upperRightLongitude, int maxResults,
2818            GeocoderParams params, List<Address> addrs) {
2819
2820        if (mGeocodeProvider != null) {
2821            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2822                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2823                    maxResults, params, addrs);
2824        }
2825        return null;
2826    }
2827
2828    // Mock Providers
2829
2830    private boolean canCallerAccessMockLocation(String opPackageName) {
2831        return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
2832                opPackageName) == AppOpsManager.MODE_ALLOWED;
2833    }
2834
2835    @Override
2836    public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
2837        if (!canCallerAccessMockLocation(opPackageName)) {
2838            return;
2839        }
2840
2841        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2842            throw new IllegalArgumentException("Cannot mock the passive location provider");
2843        }
2844
2845        long identity = Binder.clearCallingIdentity();
2846        synchronized (mLock) {
2847            // remove the real provider if we are replacing GPS or network provider
2848            if (LocationManager.GPS_PROVIDER.equals(name)
2849                    || LocationManager.NETWORK_PROVIDER.equals(name)
2850                    || LocationManager.FUSED_PROVIDER.equals(name)) {
2851                LocationProviderInterface p = mProvidersByName.get(name);
2852                if (p != null) {
2853                    removeProviderLocked(p);
2854                }
2855            }
2856            addTestProviderLocked(name, properties);
2857            updateProvidersLocked();
2858        }
2859        Binder.restoreCallingIdentity(identity);
2860    }
2861
2862    private void addTestProviderLocked(String name, ProviderProperties properties) {
2863        if (mProvidersByName.get(name) != null) {
2864            throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2865        }
2866        MockProvider provider = new MockProvider(name, this, properties);
2867        addProviderLocked(provider);
2868        mMockProviders.put(name, provider);
2869        mLastLocation.put(name, null);
2870        mLastLocationCoarseInterval.put(name, null);
2871    }
2872
2873    @Override
2874    public void removeTestProvider(String provider, String opPackageName) {
2875        if (!canCallerAccessMockLocation(opPackageName)) {
2876            return;
2877        }
2878
2879        synchronized (mLock) {
2880
2881            // These methods can't be called after removing the test provider, so first make sure
2882            // we don't leave anything dangling.
2883            clearTestProviderEnabled(provider, opPackageName);
2884            clearTestProviderLocation(provider, opPackageName);
2885            clearTestProviderStatus(provider, opPackageName);
2886
2887            MockProvider mockProvider = mMockProviders.remove(provider);
2888            if (mockProvider == null) {
2889                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2890            }
2891            long identity = Binder.clearCallingIdentity();
2892            removeProviderLocked(mProvidersByName.get(provider));
2893
2894            // reinstate real provider if available
2895            LocationProviderInterface realProvider = mRealProviders.get(provider);
2896            if (realProvider != null) {
2897                addProviderLocked(realProvider);
2898            }
2899            mLastLocation.put(provider, null);
2900            mLastLocationCoarseInterval.put(provider, null);
2901            updateProvidersLocked();
2902            Binder.restoreCallingIdentity(identity);
2903        }
2904    }
2905
2906    @Override
2907    public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
2908        if (!canCallerAccessMockLocation(opPackageName)) {
2909            return;
2910        }
2911
2912        synchronized (mLock) {
2913            MockProvider mockProvider = mMockProviders.get(provider);
2914            if (mockProvider == null) {
2915                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2916            }
2917
2918            // Ensure that the location is marked as being mock. There's some logic to do this in
2919            // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
2920            Location mock = new Location(loc);
2921            mock.setIsFromMockProvider(true);
2922
2923            if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
2924                // The location has an explicit provider that is different from the mock provider
2925                // name. The caller may be trying to fool us via bug 33091107.
2926                EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
2927                        provider + "!=" + loc.getProvider());
2928            }
2929
2930            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2931            long identity = Binder.clearCallingIdentity();
2932            mockProvider.setLocation(mock);
2933            Binder.restoreCallingIdentity(identity);
2934        }
2935    }
2936
2937    @Override
2938    public void clearTestProviderLocation(String provider, String opPackageName) {
2939        if (!canCallerAccessMockLocation(opPackageName)) {
2940            return;
2941        }
2942
2943        synchronized (mLock) {
2944            MockProvider mockProvider = mMockProviders.get(provider);
2945            if (mockProvider == null) {
2946                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2947            }
2948            mockProvider.clearLocation();
2949        }
2950    }
2951
2952    @Override
2953    public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
2954        if (!canCallerAccessMockLocation(opPackageName)) {
2955            return;
2956        }
2957
2958        synchronized (mLock) {
2959            MockProvider mockProvider = mMockProviders.get(provider);
2960            if (mockProvider == null) {
2961                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2962            }
2963            long identity = Binder.clearCallingIdentity();
2964            if (enabled) {
2965                mockProvider.enable();
2966                mEnabledProviders.add(provider);
2967                mDisabledProviders.remove(provider);
2968            } else {
2969                mockProvider.disable();
2970                mEnabledProviders.remove(provider);
2971                mDisabledProviders.add(provider);
2972            }
2973            updateProvidersLocked();
2974            Binder.restoreCallingIdentity(identity);
2975        }
2976    }
2977
2978    @Override
2979    public void clearTestProviderEnabled(String provider, String opPackageName) {
2980        if (!canCallerAccessMockLocation(opPackageName)) {
2981            return;
2982        }
2983
2984        synchronized (mLock) {
2985            MockProvider mockProvider = mMockProviders.get(provider);
2986            if (mockProvider == null) {
2987                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2988            }
2989            long identity = Binder.clearCallingIdentity();
2990            mEnabledProviders.remove(provider);
2991            mDisabledProviders.remove(provider);
2992            updateProvidersLocked();
2993            Binder.restoreCallingIdentity(identity);
2994        }
2995    }
2996
2997    @Override
2998    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
2999            String opPackageName) {
3000        if (!canCallerAccessMockLocation(opPackageName)) {
3001            return;
3002        }
3003
3004        synchronized (mLock) {
3005            MockProvider mockProvider = mMockProviders.get(provider);
3006            if (mockProvider == null) {
3007                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3008            }
3009            mockProvider.setStatus(status, extras, updateTime);
3010        }
3011    }
3012
3013    @Override
3014    public void clearTestProviderStatus(String provider, String opPackageName) {
3015        if (!canCallerAccessMockLocation(opPackageName)) {
3016            return;
3017        }
3018
3019        synchronized (mLock) {
3020            MockProvider mockProvider = mMockProviders.get(provider);
3021            if (mockProvider == null) {
3022                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3023            }
3024            mockProvider.clearStatus();
3025        }
3026    }
3027
3028    private void log(String log) {
3029        if (Log.isLoggable(TAG, Log.VERBOSE)) {
3030            Slog.d(TAG, log);
3031        }
3032    }
3033
3034    @Override
3035    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3036        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
3037
3038        synchronized (mLock) {
3039            if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3040                if (mGnssMetricsProvider != null) {
3041                    pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3042                }
3043                return;
3044            }
3045            pw.println("Current Location Manager state:");
3046            pw.println("  Location Listeners:");
3047            for (Receiver receiver : mReceivers.values()) {
3048                pw.println("    " + receiver);
3049            }
3050            pw.println("  Active Records by Provider:");
3051            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3052                pw.println("    " + entry.getKey() + ":");
3053                for (UpdateRecord record : entry.getValue()) {
3054                    pw.println("      " + record);
3055                }
3056            }
3057            pw.println("  Overlay Provider Packages:");
3058            for (LocationProviderInterface provider : mProviders) {
3059                if (provider instanceof LocationProviderProxy) {
3060                    pw.println("    " + provider.getName() + ": "
3061                            + ((LocationProviderProxy) provider).getConnectedPackageName());
3062                }
3063            }
3064            pw.println("  Historical Records by Provider:");
3065            for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3066                    : mRequestStatistics.statistics.entrySet()) {
3067                PackageProviderKey key = entry.getKey();
3068                PackageStatistics stats = entry.getValue();
3069                pw.println("    " + key.packageName + ": " + key.providerName + ": " + stats);
3070            }
3071            pw.println("  Last Known Locations:");
3072            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3073                String provider = entry.getKey();
3074                Location location = entry.getValue();
3075                pw.println("    " + provider + ": " + location);
3076            }
3077
3078            pw.println("  Last Known Locations Coarse Intervals:");
3079            for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3080                String provider = entry.getKey();
3081                Location location = entry.getValue();
3082                pw.println("    " + provider + ": " + location);
3083            }
3084
3085            mGeofenceManager.dump(pw);
3086
3087            if (mEnabledProviders.size() > 0) {
3088                pw.println("  Enabled Providers:");
3089                for (String i : mEnabledProviders) {
3090                    pw.println("    " + i);
3091                }
3092
3093            }
3094            if (mDisabledProviders.size() > 0) {
3095                pw.println("  Disabled Providers:");
3096                for (String i : mDisabledProviders) {
3097                    pw.println("    " + i);
3098                }
3099            }
3100            pw.append("  ");
3101            mBlacklist.dump(pw);
3102            if (mMockProviders.size() > 0) {
3103                pw.println("  Mock Providers:");
3104                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
3105                    i.getValue().dump(pw, "      ");
3106                }
3107            }
3108
3109            if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3110                pw.println("  Throttling Whitelisted Packages:");
3111                for (String packageName : mBackgroundThrottlePackageWhitelist) {
3112                    pw.println("    " + packageName);
3113                }
3114            }
3115
3116            pw.append("  fudger: ");
3117            mLocationFudger.dump(fd, pw,  args);
3118
3119            if (args.length > 0 && "short".equals(args[0])) {
3120                return;
3121            }
3122            for (LocationProviderInterface provider: mProviders) {
3123                pw.print(provider.getName() + " Internal State");
3124                if (provider instanceof LocationProviderProxy) {
3125                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
3126                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
3127                }
3128                pw.println(":");
3129                provider.dump(fd, pw, args);
3130            }
3131            if (mGnssBatchingInProgress) {
3132                pw.println("  GNSS batching in progress");
3133            }
3134        }
3135    }
3136}
3137