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