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