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