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