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