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