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