[go: nahoru, domu]

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
1435                        // Don't assign battery blame for update records whose
1436                        // client has no permission to receive location data.
1437                        if (!providerRequest.locationRequests.contains(locationRequest)) {
1438                            continue;
1439                        }
1440
1441                        if (locationRequest.getInterval() <= thresholdInterval) {
1442                            if (record.mReceiver.mWorkSource != null
1443                                    && record.mReceiver.mWorkSource.size() > 0
1444                                    && record.mReceiver.mWorkSource.getName(0) != null) {
1445                                // Assign blame to another work source.
1446                                // Can only assign blame if the WorkSource contains names.
1447                                worksource.add(record.mReceiver.mWorkSource);
1448                            } else {
1449                                // Assign blame to caller.
1450                                worksource.add(
1451                                        record.mReceiver.mUid,
1452                                        record.mReceiver.mPackageName);
1453                            }
1454                        }
1455                    }
1456                }
1457            }
1458        }
1459
1460        if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1461        p.setRequest(providerRequest, worksource);
1462    }
1463
1464    private class UpdateRecord {
1465        final String mProvider;
1466        final LocationRequest mRequest;
1467        final Receiver mReceiver;
1468        Location mLastFixBroadcast;
1469        long mLastStatusBroadcast;
1470
1471        /**
1472         * Note: must be constructed with lock held.
1473         */
1474        UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
1475            mProvider = provider;
1476            mRequest = request;
1477            mReceiver = receiver;
1478
1479            ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1480            if (records == null) {
1481                records = new ArrayList<UpdateRecord>();
1482                mRecordsByProvider.put(provider, records);
1483            }
1484            if (!records.contains(this)) {
1485                records.add(this);
1486            }
1487
1488            // Update statistics for historical location requests by package/provider
1489            mRequestStatistics.startRequesting(
1490                    mReceiver.mPackageName, provider, request.getInterval());
1491        }
1492
1493        /**
1494         * Method to be called when a record will no longer be used.
1495         */
1496        void disposeLocked(boolean removeReceiver) {
1497            mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1498
1499            // remove from mRecordsByProvider
1500            ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1501            if (globalRecords != null) {
1502                globalRecords.remove(this);
1503            }
1504
1505            if (!removeReceiver) return;  // the caller will handle the rest
1506
1507            // remove from Receiver#mUpdateRecords
1508            HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1509            if (receiverRecords != null) {
1510                receiverRecords.remove(this.mProvider);
1511
1512                // and also remove the Receiver if it has no more update records
1513                if (removeReceiver && receiverRecords.size() == 0) {
1514                    removeUpdatesLocked(mReceiver);
1515                }
1516            }
1517        }
1518
1519        @Override
1520        public String toString() {
1521            StringBuilder s = new StringBuilder();
1522            s.append("UpdateRecord[");
1523            s.append(mProvider);
1524            s.append(' ').append(mReceiver.mPackageName).append('(');
1525            s.append(mReceiver.mUid).append(')');
1526            s.append(' ').append(mRequest);
1527            s.append(']');
1528            return s.toString();
1529        }
1530    }
1531
1532    private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
1533            String packageName, WorkSource workSource, boolean hideFromAppOps) {
1534        IBinder binder = listener.asBinder();
1535        Receiver receiver = mReceivers.get(binder);
1536        if (receiver == null) {
1537            receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1538                    hideFromAppOps);
1539            try {
1540                receiver.getListener().asBinder().linkToDeath(receiver, 0);
1541            } catch (RemoteException e) {
1542                Slog.e(TAG, "linkToDeath failed:", e);
1543                return null;
1544            }
1545            mReceivers.put(binder, receiver);
1546        }
1547        return receiver;
1548    }
1549
1550    private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
1551            WorkSource workSource, boolean hideFromAppOps) {
1552        Receiver receiver = mReceivers.get(intent);
1553        if (receiver == null) {
1554            receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1555                    hideFromAppOps);
1556            mReceivers.put(intent, receiver);
1557        }
1558        return receiver;
1559    }
1560
1561    /**
1562     * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1563     * and consistency requirements.
1564     *
1565     * @param request the LocationRequest from which to create a sanitized version
1566     * @return a version of request that meets the given resolution and consistency requirements
1567     * @hide
1568     */
1569    private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1570        LocationRequest sanitizedRequest = new LocationRequest(request);
1571        if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1572            switch (sanitizedRequest.getQuality()) {
1573                case LocationRequest.ACCURACY_FINE:
1574                    sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
1575                    break;
1576                case LocationRequest.POWER_HIGH:
1577                    sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
1578                    break;
1579            }
1580            // throttle
1581            if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1582                sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1583            }
1584            if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1585                sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1586            }
1587        }
1588        // make getFastestInterval() the minimum of interval and fastest interval
1589        if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
1590            request.setFastestInterval(request.getInterval());
1591        }
1592        return sanitizedRequest;
1593    }
1594
1595    private void checkPackageName(String packageName) {
1596        if (packageName == null) {
1597            throw new SecurityException("invalid package name: " + packageName);
1598        }
1599        int uid = Binder.getCallingUid();
1600        String[] packages = mPackageManager.getPackagesForUid(uid);
1601        if (packages == null) {
1602            throw new SecurityException("invalid UID " + uid);
1603        }
1604        for (String pkg : packages) {
1605            if (packageName.equals(pkg)) return;
1606        }
1607        throw new SecurityException("invalid package name: " + packageName);
1608    }
1609
1610    private void checkPendingIntent(PendingIntent intent) {
1611        if (intent == null) {
1612            throw new IllegalArgumentException("invalid pending intent: " + intent);
1613        }
1614    }
1615
1616    private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
1617            int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
1618        if (intent == null && listener == null) {
1619            throw new IllegalArgumentException("need either listener or intent");
1620        } else if (intent != null && listener != null) {
1621            throw new IllegalArgumentException("cannot register both listener and intent");
1622        } else if (intent != null) {
1623            checkPendingIntent(intent);
1624            return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
1625        } else {
1626            return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
1627        }
1628    }
1629
1630    @Override
1631    public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1632            PendingIntent intent, String packageName) {
1633        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1634        checkPackageName(packageName);
1635        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1636        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1637                request.getProvider());
1638        WorkSource workSource = request.getWorkSource();
1639        if (workSource != null && workSource.size() > 0) {
1640            checkDeviceStatsAllowed();
1641        }
1642        boolean hideFromAppOps = request.getHideFromAppOps();
1643        if (hideFromAppOps) {
1644            checkUpdateAppOpsAllowed();
1645        }
1646        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
1647
1648        final int pid = Binder.getCallingPid();
1649        final int uid = Binder.getCallingUid();
1650        // providers may use public location API's, need to clear identity
1651        long identity = Binder.clearCallingIdentity();
1652        try {
1653            // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1654            // a location.
1655            checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1656
1657            synchronized (mLock) {
1658                Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
1659                        packageName, workSource, hideFromAppOps);
1660                requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
1661            }
1662        } finally {
1663            Binder.restoreCallingIdentity(identity);
1664        }
1665    }
1666
1667    private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1668            int pid, int uid, String packageName) {
1669        // Figure out the provider. Either its explicitly request (legacy use cases), or
1670        // use the fused provider
1671        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1672        String name = request.getProvider();
1673        if (name == null) {
1674            throw new IllegalArgumentException("provider name must not be null");
1675        }
1676
1677        if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1678                + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
1679        LocationProviderInterface provider = mProvidersByName.get(name);
1680        if (provider == null) {
1681            throw new IllegalArgumentException("provider doesn't exist: " + name);
1682        }
1683
1684        UpdateRecord record = new UpdateRecord(name, request, receiver);
1685        UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1686        if (oldRecord != null) {
1687            oldRecord.disposeLocked(false);
1688        }
1689
1690        boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
1691        if (isProviderEnabled) {
1692            applyRequirementsLocked(name);
1693        } else {
1694            // Notify the listener that updates are currently disabled
1695            receiver.callProviderEnabledLocked(name, false);
1696        }
1697        // Update the monitoring here just in case multiple location requests were added to the
1698        // same receiver (this request may be high power and the initial might not have been).
1699        receiver.updateMonitoring(true);
1700    }
1701
1702    @Override
1703    public void removeUpdates(ILocationListener listener, PendingIntent intent,
1704            String packageName) {
1705        checkPackageName(packageName);
1706
1707        final int pid = Binder.getCallingPid();
1708        final int uid = Binder.getCallingUid();
1709
1710        synchronized (mLock) {
1711            WorkSource workSource = null;
1712            boolean hideFromAppOps = false;
1713            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1714                    packageName, workSource, hideFromAppOps);
1715
1716            // providers may use public location API's, need to clear identity
1717            long identity = Binder.clearCallingIdentity();
1718            try {
1719                removeUpdatesLocked(receiver);
1720            } finally {
1721                Binder.restoreCallingIdentity(identity);
1722            }
1723        }
1724    }
1725
1726    private void removeUpdatesLocked(Receiver receiver) {
1727        if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1728
1729        if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1730            receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1731            synchronized (receiver) {
1732                receiver.clearPendingBroadcastsLocked();
1733            }
1734        }
1735
1736        receiver.updateMonitoring(false);
1737
1738        // Record which providers were associated with this listener
1739        HashSet<String> providers = new HashSet<String>();
1740        HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1741        if (oldRecords != null) {
1742            // Call dispose() on the obsolete update records.
1743            for (UpdateRecord record : oldRecords.values()) {
1744                // Update statistics for historical location requests by package/provider
1745                record.disposeLocked(false);
1746            }
1747            // Accumulate providers
1748            providers.addAll(oldRecords.keySet());
1749        }
1750
1751        // update provider
1752        for (String provider : providers) {
1753            // If provider is already disabled, don't need to do anything
1754            if (!isAllowedByCurrentUserSettingsLocked(provider)) {
1755                continue;
1756            }
1757
1758            applyRequirementsLocked(provider);
1759        }
1760    }
1761
1762    private void applyAllProviderRequirementsLocked() {
1763        for (LocationProviderInterface p : mProviders) {
1764            // If provider is already disabled, don't need to do anything
1765            if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
1766                continue;
1767            }
1768
1769            applyRequirementsLocked(p.getName());
1770        }
1771    }
1772
1773    @Override
1774    public Location getLastLocation(LocationRequest request, String packageName) {
1775        if (D) Log.d(TAG, "getLastLocation: " + request);
1776        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1777        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1778        checkPackageName(packageName);
1779        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1780                request.getProvider());
1781        // no need to sanitize this request, as only the provider name is used
1782
1783        final int pid = Binder.getCallingPid();
1784        final int uid = Binder.getCallingUid();
1785        final long identity = Binder.clearCallingIdentity();
1786        try {
1787            if (mBlacklist.isBlacklisted(packageName)) {
1788                if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1789                        packageName);
1790                return null;
1791            }
1792
1793            if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
1794                if (D) Log.d(TAG, "not returning last loc for no op app: " +
1795                        packageName);
1796                return null;
1797            }
1798
1799            synchronized (mLock) {
1800                // Figure out the provider. Either its explicitly request (deprecated API's),
1801                // or use the fused provider
1802                String name = request.getProvider();
1803                if (name == null) name = LocationManager.FUSED_PROVIDER;
1804                LocationProviderInterface provider = mProvidersByName.get(name);
1805                if (provider == null) return null;
1806
1807                if (!isAllowedByUserSettingsLocked(name, uid)) return null;
1808
1809                Location location;
1810                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1811                    // Make sure that an app with coarse permissions can't get frequent location
1812                    // updates by calling LocationManager.getLastKnownLocation repeatedly.
1813                    location = mLastLocationCoarseInterval.get(name);
1814                } else {
1815                    location = mLastLocation.get(name);
1816                }
1817                if (location == null) {
1818                    return null;
1819                }
1820                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1821                    Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1822                    if (noGPSLocation != null) {
1823                        return new Location(mLocationFudger.getOrCreate(noGPSLocation));
1824                    }
1825                } else {
1826                    return new Location(location);
1827                }
1828            }
1829            return null;
1830        } finally {
1831            Binder.restoreCallingIdentity(identity);
1832        }
1833    }
1834
1835    @Override
1836    public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1837            String packageName) {
1838        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1839        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1840        checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
1841        checkPendingIntent(intent);
1842        checkPackageName(packageName);
1843        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1844                request.getProvider());
1845        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
1846
1847        if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
1848
1849        // geo-fence manager uses the public location API, need to clear identity
1850        int uid = Binder.getCallingUid();
1851        // TODO: http://b/23822629
1852        if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
1853            // temporary measure until geofences work for secondary users
1854            Log.w(TAG, "proximity alerts are currently available only to the primary user");
1855            return;
1856        }
1857        long identity = Binder.clearCallingIdentity();
1858        try {
1859            mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1860                    uid, packageName);
1861        } finally {
1862            Binder.restoreCallingIdentity(identity);
1863        }
1864    }
1865
1866    @Override
1867    public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1868        checkPendingIntent(intent);
1869        checkPackageName(packageName);
1870
1871        if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1872
1873        // geo-fence manager uses the public location API, need to clear identity
1874        long identity = Binder.clearCallingIdentity();
1875        try {
1876            mGeofenceManager.removeFence(geofence, intent);
1877        } finally {
1878            Binder.restoreCallingIdentity(identity);
1879        }
1880    }
1881
1882
1883    @Override
1884    public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
1885        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1886        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1887                LocationManager.GPS_PROVIDER);
1888
1889        final int pid = Binder.getCallingPid();
1890        final int uid = Binder.getCallingUid();
1891        final long ident = Binder.clearCallingIdentity();
1892        try {
1893            if (!checkLocationAccess(pid, uid, packageName, allowedResolutionLevel)) {
1894                return false;
1895            }
1896        } finally {
1897            Binder.restoreCallingIdentity(ident);
1898        }
1899
1900        if (mGnssStatusProvider == null) {
1901            return false;
1902        }
1903
1904        try {
1905            mGnssStatusProvider.registerGnssStatusCallback(callback);
1906        } catch (RemoteException e) {
1907            Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
1908            return false;
1909        }
1910        return true;
1911    }
1912
1913    @Override
1914    public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
1915        synchronized (mLock) {
1916            try {
1917                mGnssStatusProvider.unregisterGnssStatusCallback(callback);
1918            } catch (Exception e) {
1919                Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
1920            }
1921        }
1922    }
1923
1924    @Override
1925    public boolean addGnssMeasurementsListener(
1926            IGnssMeasurementsListener listener,
1927            String packageName) {
1928        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1929        checkResolutionLevelIsSufficientForProviderUse(
1930                allowedResolutionLevel,
1931                LocationManager.GPS_PROVIDER);
1932
1933        int pid = Binder.getCallingPid();
1934        int uid = Binder.getCallingUid();
1935        long identity = Binder.clearCallingIdentity();
1936        boolean hasLocationAccess;
1937        try {
1938            hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1939        } finally {
1940            Binder.restoreCallingIdentity(identity);
1941        }
1942
1943        if (!hasLocationAccess || mGnssMeasurementsProvider == null) {
1944            return false;
1945        }
1946        return mGnssMeasurementsProvider.addListener(listener);
1947    }
1948
1949    @Override
1950    public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
1951        if (mGnssMeasurementsProvider != null) {
1952            mGnssMeasurementsProvider.removeListener(listener);
1953        }
1954    }
1955
1956    @Override
1957    public boolean addGnssNavigationMessageListener(
1958            IGnssNavigationMessageListener listener,
1959            String packageName) {
1960        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1961        checkResolutionLevelIsSufficientForProviderUse(
1962                allowedResolutionLevel,
1963                LocationManager.GPS_PROVIDER);
1964
1965        int pid = Binder.getCallingPid();
1966        int uid = Binder.getCallingUid();
1967        long identity = Binder.clearCallingIdentity();
1968        boolean hasLocationAccess;
1969        try {
1970            hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1971        } finally {
1972            Binder.restoreCallingIdentity(identity);
1973        }
1974
1975        if (!hasLocationAccess || mGnssNavigationMessageProvider == null) {
1976            return false;
1977        }
1978        return mGnssNavigationMessageProvider.addListener(listener);
1979    }
1980
1981    @Override
1982    public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
1983        if (mGnssNavigationMessageProvider != null) {
1984            mGnssNavigationMessageProvider.removeListener(listener);
1985        }
1986    }
1987
1988    @Override
1989    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1990        if (provider == null) {
1991            // throw NullPointerException to remain compatible with previous implementation
1992            throw new NullPointerException();
1993        }
1994        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1995                provider);
1996
1997        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1998        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1999                != PackageManager.PERMISSION_GRANTED)) {
2000            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2001        }
2002
2003        synchronized (mLock) {
2004            LocationProviderInterface p = mProvidersByName.get(provider);
2005            if (p == null) return false;
2006
2007            return p.sendExtraCommand(command, extras);
2008        }
2009    }
2010
2011    @Override
2012    public boolean sendNiResponse(int notifId, int userResponse) {
2013        if (Binder.getCallingUid() != Process.myUid()) {
2014            throw new SecurityException(
2015                    "calling sendNiResponse from outside of the system is not allowed");
2016        }
2017        try {
2018            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
2019        } catch (RemoteException e) {
2020            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
2021            return false;
2022        }
2023    }
2024
2025    /**
2026     * @return null if the provider does not exist
2027     * @throws SecurityException if the provider is not allowed to be
2028     * accessed by the caller
2029     */
2030    @Override
2031    public ProviderProperties getProviderProperties(String provider) {
2032        if (mProvidersByName.get(provider) == null) {
2033            return null;
2034        }
2035
2036        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2037                provider);
2038
2039        LocationProviderInterface p;
2040        synchronized (mLock) {
2041            p = mProvidersByName.get(provider);
2042        }
2043
2044        if (p == null) return null;
2045        return p.getProperties();
2046    }
2047
2048    /**
2049     * @return null if the provider does not exist
2050     * @throws SecurityException if the provider is not allowed to be
2051     * accessed by the caller
2052     */
2053    @Override
2054    public String getNetworkProviderPackage() {
2055        LocationProviderInterface p;
2056        synchronized (mLock) {
2057            if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2058                return null;
2059            }
2060            p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2061        }
2062
2063        if (p instanceof LocationProviderProxy) {
2064            return ((LocationProviderProxy) p).getConnectedPackageName();
2065        }
2066        return null;
2067    }
2068
2069    @Override
2070    public boolean isProviderEnabled(String provider) {
2071        // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2072        // so we discourage its use
2073        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2074
2075        int uid = Binder.getCallingUid();
2076        long identity = Binder.clearCallingIdentity();
2077        try {
2078            synchronized (mLock) {
2079                LocationProviderInterface p = mProvidersByName.get(provider);
2080                if (p == null) return false;
2081
2082                return isAllowedByUserSettingsLocked(provider, uid);
2083            }
2084        } finally {
2085            Binder.restoreCallingIdentity(identity);
2086        }
2087    }
2088
2089    /**
2090     * Returns "true" if the UID belongs to a bound location provider.
2091     *
2092     * @param uid the uid
2093     * @return true if uid belongs to a bound location provider
2094     */
2095    private boolean isUidALocationProvider(int uid) {
2096        if (uid == Process.SYSTEM_UID) {
2097            return true;
2098        }
2099        if (mGeocodeProvider != null) {
2100            if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
2101        }
2102        for (LocationProviderProxy proxy : mProxyProviders) {
2103            if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
2104        }
2105        return false;
2106    }
2107
2108    private void checkCallerIsProvider() {
2109        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2110                == PackageManager.PERMISSION_GRANTED) {
2111            return;
2112        }
2113
2114        // Previously we only used the INSTALL_LOCATION_PROVIDER
2115        // check. But that is system or signature
2116        // protection level which is not flexible enough for
2117        // providers installed oustide the system image. So
2118        // also allow providers with a UID matching the
2119        // currently bound package name
2120
2121        if (isUidALocationProvider(Binder.getCallingUid())) {
2122            return;
2123        }
2124
2125        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2126                "or UID of a currently bound location provider");
2127    }
2128
2129    /**
2130     * Returns true if the given package belongs to the given uid.
2131     */
2132    private boolean doesUidHavePackage(int uid, String packageName) {
2133        if (packageName == null) {
2134            return false;
2135        }
2136        String[] packageNames = mPackageManager.getPackagesForUid(uid);
2137        if (packageNames == null) {
2138            return false;
2139        }
2140        for (String name : packageNames) {
2141            if (packageName.equals(name)) {
2142                return true;
2143            }
2144        }
2145        return false;
2146    }
2147
2148    @Override
2149    public void reportLocation(Location location, boolean passive) {
2150        checkCallerIsProvider();
2151
2152        if (!location.isComplete()) {
2153            Log.w(TAG, "Dropping incomplete location: " + location);
2154            return;
2155        }
2156
2157        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2158        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
2159        m.arg1 = (passive ? 1 : 0);
2160        mLocationHandler.sendMessageAtFrontOfQueue(m);
2161    }
2162
2163
2164    private static boolean shouldBroadcastSafe(
2165            Location loc, Location lastLoc, UpdateRecord record, long now) {
2166        // Always broadcast the first update
2167        if (lastLoc == null) {
2168            return true;
2169        }
2170
2171        // Check whether sufficient time has passed
2172        long minTime = record.mRequest.getFastestInterval();
2173        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2174                / NANOS_PER_MILLI;
2175        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
2176            return false;
2177        }
2178
2179        // Check whether sufficient distance has been traveled
2180        double minDistance = record.mRequest.getSmallestDisplacement();
2181        if (minDistance > 0.0) {
2182            if (loc.distanceTo(lastLoc) <= minDistance) {
2183                return false;
2184            }
2185        }
2186
2187        // Check whether sufficient number of udpates is left
2188        if (record.mRequest.getNumUpdates() <= 0) {
2189            return false;
2190        }
2191
2192        // Check whether the expiry date has passed
2193        if (record.mRequest.getExpireAt() < now) {
2194            return false;
2195        }
2196
2197        return true;
2198    }
2199
2200    private void handleLocationChangedLocked(Location location, boolean passive) {
2201        if (D) Log.d(TAG, "incoming location: " + location);
2202
2203        long now = SystemClock.elapsedRealtime();
2204        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
2205
2206        // Skip if the provider is unknown.
2207        LocationProviderInterface p = mProvidersByName.get(provider);
2208        if (p == null) return;
2209
2210        // Update last known locations
2211        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2212        Location lastNoGPSLocation = null;
2213        Location lastLocation = mLastLocation.get(provider);
2214        if (lastLocation == null) {
2215            lastLocation = new Location(provider);
2216            mLastLocation.put(provider, lastLocation);
2217        } else {
2218            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2219            if (noGPSLocation == null && lastNoGPSLocation != null) {
2220                // New location has no no-GPS location: adopt last no-GPS location. This is set
2221                // directly into location because we do not want to notify COARSE clients.
2222                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2223            }
2224        }
2225        lastLocation.set(location);
2226
2227        // Update last known coarse interval location if enough time has passed.
2228        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2229        if (lastLocationCoarseInterval == null) {
2230            lastLocationCoarseInterval = new Location(location);
2231            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2232        }
2233        long timeDiffNanos = location.getElapsedRealtimeNanos()
2234                - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2235        if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2236            lastLocationCoarseInterval.set(location);
2237        }
2238        // Don't ever return a coarse location that is more recent than the allowed update
2239        // interval (i.e. don't allow an app to keep registering and unregistering for
2240        // location updates to overcome the minimum interval).
2241        noGPSLocation =
2242                lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2243
2244        // Skip if there are no UpdateRecords for this provider.
2245        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2246        if (records == null || records.size() == 0) return;
2247
2248        // Fetch coarse location
2249        Location coarseLocation = null;
2250        if (noGPSLocation != null) {
2251            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2252        }
2253
2254        // Fetch latest status update time
2255        long newStatusUpdateTime = p.getStatusUpdateTime();
2256
2257        // Get latest status
2258        Bundle extras = new Bundle();
2259        int status = p.getStatus(extras);
2260
2261        ArrayList<Receiver> deadReceivers = null;
2262        ArrayList<UpdateRecord> deadUpdateRecords = null;
2263
2264        // Broadcast location or status to all listeners
2265        for (UpdateRecord r : records) {
2266            Receiver receiver = r.mReceiver;
2267            boolean receiverDead = false;
2268
2269            int receiverUserId = UserHandle.getUserId(receiver.mUid);
2270            if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
2271                if (D) {
2272                    Log.d(TAG, "skipping loc update for background user " + receiverUserId +
2273                            " (current user: " + mCurrentUserId + ", app: " +
2274                            receiver.mPackageName + ")");
2275                }
2276                continue;
2277            }
2278
2279            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2280                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2281                        receiver.mPackageName);
2282                continue;
2283            }
2284
2285            if (!reportLocationAccessNoThrow(receiver.mPid, receiver.mUid, receiver.mPackageName,
2286                    receiver.mAllowedResolutionLevel)) {
2287                if (D) Log.d(TAG, "skipping loc update for no op app: " +
2288                        receiver.mPackageName);
2289                continue;
2290            }
2291
2292            Location notifyLocation = null;
2293            if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2294                notifyLocation = coarseLocation;  // use coarse location
2295            } else {
2296                notifyLocation = lastLocation;  // use fine location
2297            }
2298            if (notifyLocation != null) {
2299                Location lastLoc = r.mLastFixBroadcast;
2300                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
2301                    if (lastLoc == null) {
2302                        lastLoc = new Location(notifyLocation);
2303                        r.mLastFixBroadcast = lastLoc;
2304                    } else {
2305                        lastLoc.set(notifyLocation);
2306                    }
2307                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
2308                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2309                        receiverDead = true;
2310                    }
2311                    r.mRequest.decrementNumUpdates();
2312                }
2313            }
2314
2315            long prevStatusUpdateTime = r.mLastStatusBroadcast;
2316            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
2317                    (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
2318
2319                r.mLastStatusBroadcast = newStatusUpdateTime;
2320                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
2321                    receiverDead = true;
2322                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
2323                }
2324            }
2325
2326            // track expired records
2327            if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
2328                if (deadUpdateRecords == null) {
2329                    deadUpdateRecords = new ArrayList<UpdateRecord>();
2330                }
2331                deadUpdateRecords.add(r);
2332            }
2333            // track dead receivers
2334            if (receiverDead) {
2335                if (deadReceivers == null) {
2336                    deadReceivers = new ArrayList<Receiver>();
2337                }
2338                if (!deadReceivers.contains(receiver)) {
2339                    deadReceivers.add(receiver);
2340                }
2341            }
2342        }
2343
2344        // remove dead records and receivers outside the loop
2345        if (deadReceivers != null) {
2346            for (Receiver receiver : deadReceivers) {
2347                removeUpdatesLocked(receiver);
2348            }
2349        }
2350        if (deadUpdateRecords != null) {
2351            for (UpdateRecord r : deadUpdateRecords) {
2352                r.disposeLocked(true);
2353            }
2354            applyRequirementsLocked(provider);
2355        }
2356    }
2357
2358    private class LocationWorkerHandler extends Handler {
2359        public LocationWorkerHandler(Looper looper) {
2360            super(looper, null, true);
2361        }
2362
2363        @Override
2364        public void handleMessage(Message msg) {
2365            switch (msg.what) {
2366                case MSG_LOCATION_CHANGED:
2367                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2368                    break;
2369            }
2370        }
2371    }
2372
2373    private boolean isMockProvider(String provider) {
2374        synchronized (mLock) {
2375            return mMockProviders.containsKey(provider);
2376        }
2377    }
2378
2379    private void handleLocationChanged(Location location, boolean passive) {
2380        // create a working copy of the incoming Location so that the service can modify it without
2381        // disturbing the caller's copy
2382        Location myLocation = new Location(location);
2383        String provider = myLocation.getProvider();
2384
2385        // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2386        // bit if location did not come from a mock provider because passive/fused providers can
2387        // forward locations from mock providers, and should not grant them legitimacy in doing so.
2388        if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2389            myLocation.setIsFromMockProvider(true);
2390        }
2391
2392        synchronized (mLock) {
2393            if (isAllowedByCurrentUserSettingsLocked(provider)) {
2394                if (!passive) {
2395                    // notify passive provider of the new location
2396                    mPassiveProvider.updateLocation(myLocation);
2397                }
2398                handleLocationChangedLocked(myLocation, passive);
2399            }
2400        }
2401    }
2402
2403    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2404        @Override
2405        public void onPackageDisappeared(String packageName, int reason) {
2406            // remove all receivers associated with this package name
2407            synchronized (mLock) {
2408                ArrayList<Receiver> deadReceivers = null;
2409
2410                for (Receiver receiver : mReceivers.values()) {
2411                    if (receiver.mPackageName.equals(packageName)) {
2412                        if (deadReceivers == null) {
2413                            deadReceivers = new ArrayList<Receiver>();
2414                        }
2415                        deadReceivers.add(receiver);
2416                    }
2417                }
2418
2419                // perform removal outside of mReceivers loop
2420                if (deadReceivers != null) {
2421                    for (Receiver receiver : deadReceivers) {
2422                        removeUpdatesLocked(receiver);
2423                    }
2424                }
2425            }
2426        }
2427    };
2428
2429    // Geocoder
2430
2431    @Override
2432    public boolean geocoderIsPresent() {
2433        return mGeocodeProvider != null;
2434    }
2435
2436    @Override
2437    public String getFromLocation(double latitude, double longitude, int maxResults,
2438            GeocoderParams params, List<Address> addrs) {
2439        if (mGeocodeProvider != null) {
2440            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2441                    params, addrs);
2442        }
2443        return null;
2444    }
2445
2446
2447    @Override
2448    public String getFromLocationName(String locationName,
2449            double lowerLeftLatitude, double lowerLeftLongitude,
2450            double upperRightLatitude, double upperRightLongitude, int maxResults,
2451            GeocoderParams params, List<Address> addrs) {
2452
2453        if (mGeocodeProvider != null) {
2454            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2455                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2456                    maxResults, params, addrs);
2457        }
2458        return null;
2459    }
2460
2461    // Mock Providers
2462
2463    private boolean canCallerAccessMockLocation(String opPackageName) {
2464        return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
2465                opPackageName) == AppOpsManager.MODE_ALLOWED;
2466    }
2467
2468    @Override
2469    public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
2470        if (!canCallerAccessMockLocation(opPackageName)) {
2471            return;
2472        }
2473
2474        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2475            throw new IllegalArgumentException("Cannot mock the passive location provider");
2476        }
2477
2478        long identity = Binder.clearCallingIdentity();
2479        synchronized (mLock) {
2480            // remove the real provider if we are replacing GPS or network provider
2481            if (LocationManager.GPS_PROVIDER.equals(name)
2482                    || LocationManager.NETWORK_PROVIDER.equals(name)
2483                    || LocationManager.FUSED_PROVIDER.equals(name)) {
2484                LocationProviderInterface p = mProvidersByName.get(name);
2485                if (p != null) {
2486                    removeProviderLocked(p);
2487                }
2488            }
2489            addTestProviderLocked(name, properties);
2490            updateProvidersLocked();
2491        }
2492        Binder.restoreCallingIdentity(identity);
2493    }
2494
2495    private void addTestProviderLocked(String name, ProviderProperties properties) {
2496        if (mProvidersByName.get(name) != null) {
2497            throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2498        }
2499        MockProvider provider = new MockProvider(name, this, properties);
2500        addProviderLocked(provider);
2501        mMockProviders.put(name, provider);
2502        mLastLocation.put(name, null);
2503        mLastLocationCoarseInterval.put(name, null);
2504    }
2505
2506    @Override
2507    public void removeTestProvider(String provider, String opPackageName) {
2508        if (!canCallerAccessMockLocation(opPackageName)) {
2509            return;
2510        }
2511
2512        synchronized (mLock) {
2513
2514            // These methods can't be called after removing the test provider, so first make sure
2515            // we don't leave anything dangling.
2516            clearTestProviderEnabled(provider, opPackageName);
2517            clearTestProviderLocation(provider, opPackageName);
2518            clearTestProviderStatus(provider, opPackageName);
2519
2520            MockProvider mockProvider = mMockProviders.remove(provider);
2521            if (mockProvider == null) {
2522                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2523            }
2524            long identity = Binder.clearCallingIdentity();
2525            removeProviderLocked(mProvidersByName.get(provider));
2526
2527            // reinstate real provider if available
2528            LocationProviderInterface realProvider = mRealProviders.get(provider);
2529            if (realProvider != null) {
2530                addProviderLocked(realProvider);
2531            }
2532            mLastLocation.put(provider, null);
2533            mLastLocationCoarseInterval.put(provider, null);
2534            updateProvidersLocked();
2535            Binder.restoreCallingIdentity(identity);
2536        }
2537    }
2538
2539    @Override
2540    public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
2541        if (!canCallerAccessMockLocation(opPackageName)) {
2542            return;
2543        }
2544
2545        synchronized (mLock) {
2546            MockProvider mockProvider = mMockProviders.get(provider);
2547            if (mockProvider == null) {
2548                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2549            }
2550            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2551            long identity = Binder.clearCallingIdentity();
2552            mockProvider.setLocation(loc);
2553            Binder.restoreCallingIdentity(identity);
2554        }
2555    }
2556
2557    @Override
2558    public void clearTestProviderLocation(String provider, String opPackageName) {
2559        if (!canCallerAccessMockLocation(opPackageName)) {
2560            return;
2561        }
2562
2563        synchronized (mLock) {
2564            MockProvider mockProvider = mMockProviders.get(provider);
2565            if (mockProvider == null) {
2566                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2567            }
2568            mockProvider.clearLocation();
2569        }
2570    }
2571
2572    @Override
2573    public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
2574        if (!canCallerAccessMockLocation(opPackageName)) {
2575            return;
2576        }
2577
2578        synchronized (mLock) {
2579            MockProvider mockProvider = mMockProviders.get(provider);
2580            if (mockProvider == null) {
2581                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2582            }
2583            long identity = Binder.clearCallingIdentity();
2584            if (enabled) {
2585                mockProvider.enable();
2586                mEnabledProviders.add(provider);
2587                mDisabledProviders.remove(provider);
2588            } else {
2589                mockProvider.disable();
2590                mEnabledProviders.remove(provider);
2591                mDisabledProviders.add(provider);
2592            }
2593            updateProvidersLocked();
2594            Binder.restoreCallingIdentity(identity);
2595        }
2596    }
2597
2598    @Override
2599    public void clearTestProviderEnabled(String provider, String opPackageName) {
2600        if (!canCallerAccessMockLocation(opPackageName)) {
2601            return;
2602        }
2603
2604        synchronized (mLock) {
2605            MockProvider mockProvider = mMockProviders.get(provider);
2606            if (mockProvider == null) {
2607                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2608            }
2609            long identity = Binder.clearCallingIdentity();
2610            mEnabledProviders.remove(provider);
2611            mDisabledProviders.remove(provider);
2612            updateProvidersLocked();
2613            Binder.restoreCallingIdentity(identity);
2614        }
2615    }
2616
2617    @Override
2618    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
2619            String opPackageName) {
2620        if (!canCallerAccessMockLocation(opPackageName)) {
2621            return;
2622        }
2623
2624        synchronized (mLock) {
2625            MockProvider mockProvider = mMockProviders.get(provider);
2626            if (mockProvider == null) {
2627                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2628            }
2629            mockProvider.setStatus(status, extras, updateTime);
2630        }
2631    }
2632
2633    @Override
2634    public void clearTestProviderStatus(String provider, String opPackageName) {
2635        if (!canCallerAccessMockLocation(opPackageName)) {
2636            return;
2637        }
2638
2639        synchronized (mLock) {
2640            MockProvider mockProvider = mMockProviders.get(provider);
2641            if (mockProvider == null) {
2642                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2643            }
2644            mockProvider.clearStatus();
2645        }
2646    }
2647
2648    private void log(String log) {
2649        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2650            Slog.d(TAG, log);
2651        }
2652    }
2653
2654    @Override
2655    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2656        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2657                != PackageManager.PERMISSION_GRANTED) {
2658            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2659                    + Binder.getCallingPid()
2660                    + ", uid=" + Binder.getCallingUid());
2661            return;
2662        }
2663
2664        synchronized (mLock) {
2665            pw.println("Current Location Manager state:");
2666            pw.println("  Location Listeners:");
2667            for (Receiver receiver : mReceivers.values()) {
2668                pw.println("    " + receiver);
2669            }
2670            pw.println("  Active Records by Provider:");
2671            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2672                pw.println("    " + entry.getKey() + ":");
2673                for (UpdateRecord record : entry.getValue()) {
2674                    pw.println("      " + record);
2675                }
2676            }
2677            pw.println("  Historical Records by Provider:");
2678            for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2679                    : mRequestStatistics.statistics.entrySet()) {
2680                PackageProviderKey key = entry.getKey();
2681                PackageStatistics stats = entry.getValue();
2682                pw.println("    " + key.packageName + ": " + key.providerName + ": " + stats);
2683            }
2684            pw.println("  Last Known Locations:");
2685            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2686                String provider = entry.getKey();
2687                Location location = entry.getValue();
2688                pw.println("    " + provider + ": " + location);
2689            }
2690
2691            pw.println("  Last Known Locations Coarse Intervals:");
2692            for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2693                String provider = entry.getKey();
2694                Location location = entry.getValue();
2695                pw.println("    " + provider + ": " + location);
2696            }
2697
2698            mGeofenceManager.dump(pw);
2699
2700            if (mEnabledProviders.size() > 0) {
2701                pw.println("  Enabled Providers:");
2702                for (String i : mEnabledProviders) {
2703                    pw.println("    " + i);
2704                }
2705
2706            }
2707            if (mDisabledProviders.size() > 0) {
2708                pw.println("  Disabled Providers:");
2709                for (String i : mDisabledProviders) {
2710                    pw.println("    " + i);
2711                }
2712            }
2713            pw.append("  ");
2714            mBlacklist.dump(pw);
2715            if (mMockProviders.size() > 0) {
2716                pw.println("  Mock Providers:");
2717                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2718                    i.getValue().dump(pw, "      ");
2719                }
2720            }
2721
2722            pw.append("  fudger: ");
2723            mLocationFudger.dump(fd, pw,  args);
2724
2725            if (args.length > 0 && "short".equals(args[0])) {
2726                return;
2727            }
2728            for (LocationProviderInterface provider: mProviders) {
2729                pw.print(provider.getName() + " Internal State");
2730                if (provider instanceof LocationProviderProxy) {
2731                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
2732                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
2733                }
2734                pw.println(":");
2735                provider.dump(fd, pw, args);
2736            }
2737        }
2738    }
2739}
2740