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