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