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