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