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