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