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