LocationManagerService.java revision cb3ab221f72fa10a3c72142dd7567161fb9af878
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            try {
1454                receiver.getListener().asBinder().linkToDeath(receiver, 0);
1455            } catch (RemoteException e) {
1456                Slog.e(TAG, "linkToDeath failed:", e);
1457                return null;
1458            }
1459            mReceivers.put(binder, receiver);
1460        }
1461        return receiver;
1462    }
1463
1464    private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
1465            WorkSource workSource, boolean hideFromAppOps) {
1466        Receiver receiver = mReceivers.get(intent);
1467        if (receiver == null) {
1468            receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1469                    hideFromAppOps);
1470            mReceivers.put(intent, receiver);
1471        }
1472        return receiver;
1473    }
1474
1475    /**
1476     * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1477     * and consistency requirements.
1478     *
1479     * @param request the LocationRequest from which to create a sanitized version
1480     * @return a version of request that meets the given resolution and consistency requirements
1481     * @hide
1482     */
1483    private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1484        LocationRequest sanitizedRequest = new LocationRequest(request);
1485        if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1486            switch (sanitizedRequest.getQuality()) {
1487                case LocationRequest.ACCURACY_FINE:
1488                    sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
1489                    break;
1490                case LocationRequest.POWER_HIGH:
1491                    sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
1492                    break;
1493            }
1494            // throttle
1495            if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1496                sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1497            }
1498            if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1499                sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1500            }
1501        }
1502        // make getFastestInterval() the minimum of interval and fastest interval
1503        if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
1504            request.setFastestInterval(request.getInterval());
1505        }
1506        return sanitizedRequest;
1507    }
1508
1509    private void checkPackageName(String packageName) {
1510        if (packageName == null) {
1511            throw new SecurityException("invalid package name: " + packageName);
1512        }
1513        int uid = Binder.getCallingUid();
1514        String[] packages = mPackageManager.getPackagesForUid(uid);
1515        if (packages == null) {
1516            throw new SecurityException("invalid UID " + uid);
1517        }
1518        for (String pkg : packages) {
1519            if (packageName.equals(pkg)) return;
1520        }
1521        throw new SecurityException("invalid package name: " + packageName);
1522    }
1523
1524    private void checkPendingIntent(PendingIntent intent) {
1525        if (intent == null) {
1526            throw new IllegalArgumentException("invalid pending intent: " + intent);
1527        }
1528    }
1529
1530    private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
1531            int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
1532        if (intent == null && listener == null) {
1533            throw new IllegalArgumentException("need either listener or intent");
1534        } else if (intent != null && listener != null) {
1535            throw new IllegalArgumentException("cannot register both listener and intent");
1536        } else if (intent != null) {
1537            checkPendingIntent(intent);
1538            return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
1539        } else {
1540            return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
1541        }
1542    }
1543
1544    @Override
1545    public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1546            PendingIntent intent, String packageName) {
1547        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1548        checkPackageName(packageName);
1549        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1550        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1551                request.getProvider());
1552        WorkSource workSource = request.getWorkSource();
1553        if (workSource != null && workSource.size() > 0) {
1554            checkDeviceStatsAllowed();
1555        }
1556        boolean hideFromAppOps = request.getHideFromAppOps();
1557        if (hideFromAppOps) {
1558            checkUpdateAppOpsAllowed();
1559        }
1560        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
1561
1562        final int pid = Binder.getCallingPid();
1563        final int uid = Binder.getCallingUid();
1564        // providers may use public location API's, need to clear identity
1565        long identity = Binder.clearCallingIdentity();
1566        try {
1567            // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1568            // a location.
1569            checkLocationAccess(uid, packageName, allowedResolutionLevel);
1570
1571            synchronized (mLock) {
1572                Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
1573                        packageName, workSource, hideFromAppOps);
1574                requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
1575            }
1576        } finally {
1577            Binder.restoreCallingIdentity(identity);
1578        }
1579    }
1580
1581    private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1582            int pid, int uid, String packageName) {
1583        // Figure out the provider. Either its explicitly request (legacy use cases), or
1584        // use the fused provider
1585        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1586        String name = request.getProvider();
1587        if (name == null) {
1588            throw new IllegalArgumentException("provider name must not be null");
1589        }
1590
1591        if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1592                + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
1593        LocationProviderInterface provider = mProvidersByName.get(name);
1594        if (provider == null) {
1595            throw new IllegalArgumentException("provider doesn't exist: " + name);
1596        }
1597
1598        UpdateRecord record = new UpdateRecord(name, request, receiver);
1599        UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1600        if (oldRecord != null) {
1601            oldRecord.disposeLocked(false);
1602        }
1603
1604        boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
1605        if (isProviderEnabled) {
1606            applyRequirementsLocked(name);
1607        } else {
1608            // Notify the listener that updates are currently disabled
1609            receiver.callProviderEnabledLocked(name, false);
1610        }
1611        // Update the monitoring here just in case multiple location requests were added to the
1612        // same receiver (this request may be high power and the initial might not have been).
1613        receiver.updateMonitoring(true);
1614    }
1615
1616    @Override
1617    public void removeUpdates(ILocationListener listener, PendingIntent intent,
1618            String packageName) {
1619        checkPackageName(packageName);
1620
1621        final int pid = Binder.getCallingPid();
1622        final int uid = Binder.getCallingUid();
1623
1624        synchronized (mLock) {
1625            WorkSource workSource = null;
1626            boolean hideFromAppOps = false;
1627            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1628                    packageName, workSource, hideFromAppOps);
1629
1630            // providers may use public location API's, need to clear identity
1631            long identity = Binder.clearCallingIdentity();
1632            try {
1633                removeUpdatesLocked(receiver);
1634            } finally {
1635                Binder.restoreCallingIdentity(identity);
1636            }
1637        }
1638    }
1639
1640    private void removeUpdatesLocked(Receiver receiver) {
1641        if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1642
1643        if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1644            receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1645            synchronized (receiver) {
1646                receiver.clearPendingBroadcastsLocked();
1647            }
1648        }
1649
1650        receiver.updateMonitoring(false);
1651
1652        // Record which providers were associated with this listener
1653        HashSet<String> providers = new HashSet<String>();
1654        HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1655        if (oldRecords != null) {
1656            // Call dispose() on the obsolete update records.
1657            for (UpdateRecord record : oldRecords.values()) {
1658                // Update statistics for historical location requests by package/provider
1659                record.disposeLocked(false);
1660            }
1661            // Accumulate providers
1662            providers.addAll(oldRecords.keySet());
1663        }
1664
1665        // update provider
1666        for (String provider : providers) {
1667            // If provider is already disabled, don't need to do anything
1668            if (!isAllowedByCurrentUserSettingsLocked(provider)) {
1669                continue;
1670            }
1671
1672            applyRequirementsLocked(provider);
1673        }
1674    }
1675
1676    private void applyAllProviderRequirementsLocked() {
1677        for (LocationProviderInterface p : mProviders) {
1678            // If provider is already disabled, don't need to do anything
1679            if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
1680                continue;
1681            }
1682
1683            applyRequirementsLocked(p.getName());
1684        }
1685    }
1686
1687    @Override
1688    public Location getLastLocation(LocationRequest request, String packageName) {
1689        if (D) Log.d(TAG, "getLastLocation: " + request);
1690        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1691        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1692        checkPackageName(packageName);
1693        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1694                request.getProvider());
1695        // no need to sanitize this request, as only the provider name is used
1696
1697        final int uid = Binder.getCallingUid();
1698        final long identity = Binder.clearCallingIdentity();
1699        try {
1700            if (mBlacklist.isBlacklisted(packageName)) {
1701                if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1702                        packageName);
1703                return null;
1704            }
1705
1706            if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1707                if (D) Log.d(TAG, "not returning last loc for no op app: " +
1708                        packageName);
1709                return null;
1710            }
1711
1712            synchronized (mLock) {
1713                // Figure out the provider. Either its explicitly request (deprecated API's),
1714                // or use the fused provider
1715                String name = request.getProvider();
1716                if (name == null) name = LocationManager.FUSED_PROVIDER;
1717                LocationProviderInterface provider = mProvidersByName.get(name);
1718                if (provider == null) return null;
1719
1720                if (!isAllowedByUserSettingsLocked(name, uid)) return null;
1721
1722                Location location;
1723                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1724                    // Make sure that an app with coarse permissions can't get frequent location
1725                    // updates by calling LocationManager.getLastKnownLocation repeatedly.
1726                    location = mLastLocationCoarseInterval.get(name);
1727                } else {
1728                    location = mLastLocation.get(name);
1729                }
1730                if (location == null) {
1731                    return null;
1732                }
1733                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1734                    Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1735                    if (noGPSLocation != null) {
1736                        return new Location(mLocationFudger.getOrCreate(noGPSLocation));
1737                    }
1738                } else {
1739                    return new Location(location);
1740                }
1741            }
1742            return null;
1743        } finally {
1744            Binder.restoreCallingIdentity(identity);
1745        }
1746    }
1747
1748    @Override
1749    public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1750            String packageName) {
1751        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1752        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1753        checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
1754        checkPendingIntent(intent);
1755        checkPackageName(packageName);
1756        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1757                request.getProvider());
1758        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
1759
1760        if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
1761
1762        // geo-fence manager uses the public location API, need to clear identity
1763        int uid = Binder.getCallingUid();
1764        if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1765            // temporary measure until geofences work for secondary users
1766            Log.w(TAG, "proximity alerts are currently available only to the primary user");
1767            return;
1768        }
1769        long identity = Binder.clearCallingIdentity();
1770        try {
1771            mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1772                    uid, packageName);
1773        } finally {
1774            Binder.restoreCallingIdentity(identity);
1775        }
1776    }
1777
1778    @Override
1779    public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1780        checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
1781        checkPendingIntent(intent);
1782        checkPackageName(packageName);
1783
1784        if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1785
1786        // geo-fence manager uses the public location API, need to clear identity
1787        long identity = Binder.clearCallingIdentity();
1788        try {
1789            mGeofenceManager.removeFence(geofence, intent);
1790        } finally {
1791            Binder.restoreCallingIdentity(identity);
1792        }
1793    }
1794
1795
1796    @Override
1797    public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
1798        if (mGpsStatusProvider == null) {
1799            return false;
1800        }
1801        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1802        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1803                LocationManager.GPS_PROVIDER);
1804
1805        final int uid = Binder.getCallingUid();
1806        final long ident = Binder.clearCallingIdentity();
1807        try {
1808            if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
1809                return false;
1810            }
1811        } finally {
1812            Binder.restoreCallingIdentity(ident);
1813        }
1814
1815        try {
1816            mGpsStatusProvider.addGpsStatusListener(listener);
1817        } catch (RemoteException e) {
1818            Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
1819            return false;
1820        }
1821        return true;
1822    }
1823
1824    @Override
1825    public void removeGpsStatusListener(IGpsStatusListener listener) {
1826        synchronized (mLock) {
1827            try {
1828                mGpsStatusProvider.removeGpsStatusListener(listener);
1829            } catch (Exception e) {
1830                Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1831            }
1832        }
1833    }
1834
1835    @Override
1836    public boolean addGpsMeasurementsListener(
1837            IGpsMeasurementsListener listener,
1838            String packageName) {
1839        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1840        checkResolutionLevelIsSufficientForProviderUse(
1841                allowedResolutionLevel,
1842                LocationManager.GPS_PROVIDER);
1843
1844        int uid = Binder.getCallingUid();
1845        long identity = Binder.clearCallingIdentity();
1846        boolean hasLocationAccess;
1847        try {
1848            hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
1849        } finally {
1850            Binder.restoreCallingIdentity(identity);
1851        }
1852
1853        if (!hasLocationAccess) {
1854            return false;
1855        }
1856        return mGpsMeasurementsProvider.addListener(listener);
1857    }
1858
1859    @Override
1860    public boolean removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
1861        return mGpsMeasurementsProvider.removeListener(listener);
1862    }
1863
1864    @Override
1865    public boolean addGpsNavigationMessageListener(
1866            IGpsNavigationMessageListener listener,
1867            String packageName) {
1868        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1869        checkResolutionLevelIsSufficientForProviderUse(
1870                allowedResolutionLevel,
1871                LocationManager.GPS_PROVIDER);
1872
1873        int uid = Binder.getCallingUid();
1874        long identity = Binder.clearCallingIdentity();
1875        boolean hasLocationAccess;
1876        try {
1877            hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
1878        } finally {
1879            Binder.restoreCallingIdentity(identity);
1880        }
1881
1882        if (!hasLocationAccess) {
1883            return false;
1884        }
1885        return mGpsNavigationMessageProvider.addListener(listener);
1886    }
1887
1888    @Override
1889    public boolean removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
1890        return mGpsNavigationMessageProvider.removeListener(listener);
1891    }
1892
1893    @Override
1894    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1895        if (provider == null) {
1896            // throw NullPointerException to remain compatible with previous implementation
1897            throw new NullPointerException();
1898        }
1899        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1900                provider);
1901
1902        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1903        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1904                != PackageManager.PERMISSION_GRANTED)) {
1905            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1906        }
1907
1908        synchronized (mLock) {
1909            LocationProviderInterface p = mProvidersByName.get(provider);
1910            if (p == null) return false;
1911
1912            return p.sendExtraCommand(command, extras);
1913        }
1914    }
1915
1916    @Override
1917    public boolean sendNiResponse(int notifId, int userResponse) {
1918        if (Binder.getCallingUid() != Process.myUid()) {
1919            throw new SecurityException(
1920                    "calling sendNiResponse from outside of the system is not allowed");
1921        }
1922        try {
1923            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1924        } catch (RemoteException e) {
1925            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1926            return false;
1927        }
1928    }
1929
1930    /**
1931     * @return null if the provider does not exist
1932     * @throws SecurityException if the provider is not allowed to be
1933     * accessed by the caller
1934     */
1935    @Override
1936    public ProviderProperties getProviderProperties(String provider) {
1937        if (mProvidersByName.get(provider) == null) {
1938            return null;
1939        }
1940
1941        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1942                provider);
1943
1944        LocationProviderInterface p;
1945        synchronized (mLock) {
1946            p = mProvidersByName.get(provider);
1947        }
1948
1949        if (p == null) return null;
1950        return p.getProperties();
1951    }
1952
1953    @Override
1954    public boolean isProviderEnabled(String provider) {
1955        // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
1956        // so we discourage its use
1957        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1958
1959        int uid = Binder.getCallingUid();
1960        long identity = Binder.clearCallingIdentity();
1961        try {
1962            synchronized (mLock) {
1963                LocationProviderInterface p = mProvidersByName.get(provider);
1964                if (p == null) return false;
1965
1966                return isAllowedByUserSettingsLocked(provider, uid);
1967            }
1968        } finally {
1969            Binder.restoreCallingIdentity(identity);
1970        }
1971    }
1972
1973    /**
1974     * Returns "true" if the UID belongs to a bound location provider.
1975     *
1976     * @param uid the uid
1977     * @return true if uid belongs to a bound location provider
1978     */
1979    private boolean isUidALocationProvider(int uid) {
1980        if (uid == Process.SYSTEM_UID) {
1981            return true;
1982        }
1983        if (mGeocodeProvider != null) {
1984            if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1985        }
1986        for (LocationProviderProxy proxy : mProxyProviders) {
1987            if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
1988        }
1989        return false;
1990    }
1991
1992    private void checkCallerIsProvider() {
1993        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1994                == PackageManager.PERMISSION_GRANTED) {
1995            return;
1996        }
1997
1998        // Previously we only used the INSTALL_LOCATION_PROVIDER
1999        // check. But that is system or signature
2000        // protection level which is not flexible enough for
2001        // providers installed oustide the system image. So
2002        // also allow providers with a UID matching the
2003        // currently bound package name
2004
2005        if (isUidALocationProvider(Binder.getCallingUid())) {
2006            return;
2007        }
2008
2009        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2010                "or UID of a currently bound location provider");
2011    }
2012
2013    /**
2014     * Returns true if the given package belongs to the given uid.
2015     */
2016    private boolean doesUidHavePackage(int uid, String packageName) {
2017        if (packageName == null) {
2018            return false;
2019        }
2020        String[] packageNames = mPackageManager.getPackagesForUid(uid);
2021        if (packageNames == null) {
2022            return false;
2023        }
2024        for (String name : packageNames) {
2025            if (packageName.equals(name)) {
2026                return true;
2027            }
2028        }
2029        return false;
2030    }
2031
2032    @Override
2033    public void reportLocation(Location location, boolean passive) {
2034        checkCallerIsProvider();
2035
2036        if (!location.isComplete()) {
2037            Log.w(TAG, "Dropping incomplete location: " + location);
2038            return;
2039        }
2040
2041        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2042        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
2043        m.arg1 = (passive ? 1 : 0);
2044        mLocationHandler.sendMessageAtFrontOfQueue(m);
2045    }
2046
2047
2048    private static boolean shouldBroadcastSafe(
2049            Location loc, Location lastLoc, UpdateRecord record, long now) {
2050        // Always broadcast the first update
2051        if (lastLoc == null) {
2052            return true;
2053        }
2054
2055        // Check whether sufficient time has passed
2056        long minTime = record.mRequest.getFastestInterval();
2057        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2058                / NANOS_PER_MILLI;
2059        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
2060            return false;
2061        }
2062
2063        // Check whether sufficient distance has been traveled
2064        double minDistance = record.mRequest.getSmallestDisplacement();
2065        if (minDistance > 0.0) {
2066            if (loc.distanceTo(lastLoc) <= minDistance) {
2067                return false;
2068            }
2069        }
2070
2071        // Check whether sufficient number of udpates is left
2072        if (record.mRequest.getNumUpdates() <= 0) {
2073            return false;
2074        }
2075
2076        // Check whether the expiry date has passed
2077        if (record.mRequest.getExpireAt() < now) {
2078            return false;
2079        }
2080
2081        return true;
2082    }
2083
2084    private void handleLocationChangedLocked(Location location, boolean passive) {
2085        if (D) Log.d(TAG, "incoming location: " + location);
2086
2087        long now = SystemClock.elapsedRealtime();
2088        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
2089
2090        // Skip if the provider is unknown.
2091        LocationProviderInterface p = mProvidersByName.get(provider);
2092        if (p == null) return;
2093
2094        // Update last known locations
2095        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2096        Location lastNoGPSLocation = null;
2097        Location lastLocation = mLastLocation.get(provider);
2098        if (lastLocation == null) {
2099            lastLocation = new Location(provider);
2100            mLastLocation.put(provider, lastLocation);
2101        } else {
2102            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2103            if (noGPSLocation == null && lastNoGPSLocation != null) {
2104                // New location has no no-GPS location: adopt last no-GPS location. This is set
2105                // directly into location because we do not want to notify COARSE clients.
2106                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2107            }
2108        }
2109        lastLocation.set(location);
2110
2111        // Update last known coarse interval location if enough time has passed.
2112        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2113        if (lastLocationCoarseInterval == null) {
2114            lastLocationCoarseInterval = new Location(location);
2115            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2116        }
2117        long timeDiffNanos = location.getElapsedRealtimeNanos()
2118                - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2119        if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2120            lastLocationCoarseInterval.set(location);
2121        }
2122        // Don't ever return a coarse location that is more recent than the allowed update
2123        // interval (i.e. don't allow an app to keep registering and unregistering for
2124        // location updates to overcome the minimum interval).
2125        noGPSLocation =
2126                lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2127
2128        // Skip if there are no UpdateRecords for this provider.
2129        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2130        if (records == null || records.size() == 0) return;
2131
2132        // Fetch coarse location
2133        Location coarseLocation = null;
2134        if (noGPSLocation != null) {
2135            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2136        }
2137
2138        // Fetch latest status update time
2139        long newStatusUpdateTime = p.getStatusUpdateTime();
2140
2141        // Get latest status
2142        Bundle extras = new Bundle();
2143        int status = p.getStatus(extras);
2144
2145        ArrayList<Receiver> deadReceivers = null;
2146        ArrayList<UpdateRecord> deadUpdateRecords = null;
2147
2148        // Broadcast location or status to all listeners
2149        for (UpdateRecord r : records) {
2150            Receiver receiver = r.mReceiver;
2151            boolean receiverDead = false;
2152
2153            int receiverUserId = UserHandle.getUserId(receiver.mUid);
2154            if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
2155                if (D) {
2156                    Log.d(TAG, "skipping loc update for background user " + receiverUserId +
2157                            " (current user: " + mCurrentUserId + ", app: " +
2158                            receiver.mPackageName + ")");
2159                }
2160                continue;
2161            }
2162
2163            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2164                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2165                        receiver.mPackageName);
2166                continue;
2167            }
2168
2169            if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
2170                    receiver.mAllowedResolutionLevel)) {
2171                if (D) Log.d(TAG, "skipping loc update for no op app: " +
2172                        receiver.mPackageName);
2173                continue;
2174            }
2175
2176            Location notifyLocation = null;
2177            if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2178                notifyLocation = coarseLocation;  // use coarse location
2179            } else {
2180                notifyLocation = lastLocation;  // use fine location
2181            }
2182            if (notifyLocation != null) {
2183                Location lastLoc = r.mLastFixBroadcast;
2184                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
2185                    if (lastLoc == null) {
2186                        lastLoc = new Location(notifyLocation);
2187                        r.mLastFixBroadcast = lastLoc;
2188                    } else {
2189                        lastLoc.set(notifyLocation);
2190                    }
2191                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
2192                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2193                        receiverDead = true;
2194                    }
2195                    r.mRequest.decrementNumUpdates();
2196                }
2197            }
2198
2199            long prevStatusUpdateTime = r.mLastStatusBroadcast;
2200            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
2201                    (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
2202
2203                r.mLastStatusBroadcast = newStatusUpdateTime;
2204                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
2205                    receiverDead = true;
2206                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
2207                }
2208            }
2209
2210            // track expired records
2211            if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
2212                if (deadUpdateRecords == null) {
2213                    deadUpdateRecords = new ArrayList<UpdateRecord>();
2214                }
2215                deadUpdateRecords.add(r);
2216            }
2217            // track dead receivers
2218            if (receiverDead) {
2219                if (deadReceivers == null) {
2220                    deadReceivers = new ArrayList<Receiver>();
2221                }
2222                if (!deadReceivers.contains(receiver)) {
2223                    deadReceivers.add(receiver);
2224                }
2225            }
2226        }
2227
2228        // remove dead records and receivers outside the loop
2229        if (deadReceivers != null) {
2230            for (Receiver receiver : deadReceivers) {
2231                removeUpdatesLocked(receiver);
2232            }
2233        }
2234        if (deadUpdateRecords != null) {
2235            for (UpdateRecord r : deadUpdateRecords) {
2236                r.disposeLocked(true);
2237            }
2238            applyRequirementsLocked(provider);
2239        }
2240    }
2241
2242    private class LocationWorkerHandler extends Handler {
2243        public LocationWorkerHandler(Looper looper) {
2244            super(looper, null, true);
2245        }
2246
2247        @Override
2248        public void handleMessage(Message msg) {
2249            switch (msg.what) {
2250                case MSG_LOCATION_CHANGED:
2251                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2252                    break;
2253            }
2254        }
2255    }
2256
2257    private boolean isMockProvider(String provider) {
2258        synchronized (mLock) {
2259            return mMockProviders.containsKey(provider);
2260        }
2261    }
2262
2263    private void handleLocationChanged(Location location, boolean passive) {
2264        // create a working copy of the incoming Location so that the service can modify it without
2265        // disturbing the caller's copy
2266        Location myLocation = new Location(location);
2267        String provider = myLocation.getProvider();
2268
2269        // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2270        // bit if location did not come from a mock provider because passive/fused providers can
2271        // forward locations from mock providers, and should not grant them legitimacy in doing so.
2272        if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2273            myLocation.setIsFromMockProvider(true);
2274        }
2275
2276        synchronized (mLock) {
2277            if (isAllowedByCurrentUserSettingsLocked(provider)) {
2278                if (!passive) {
2279                    // notify passive provider of the new location
2280                    mPassiveProvider.updateLocation(myLocation);
2281                }
2282                handleLocationChangedLocked(myLocation, passive);
2283            }
2284        }
2285    }
2286
2287    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2288        @Override
2289        public void onPackageDisappeared(String packageName, int reason) {
2290            // remove all receivers associated with this package name
2291            synchronized (mLock) {
2292                ArrayList<Receiver> deadReceivers = null;
2293
2294                for (Receiver receiver : mReceivers.values()) {
2295                    if (receiver.mPackageName.equals(packageName)) {
2296                        if (deadReceivers == null) {
2297                            deadReceivers = new ArrayList<Receiver>();
2298                        }
2299                        deadReceivers.add(receiver);
2300                    }
2301                }
2302
2303                // perform removal outside of mReceivers loop
2304                if (deadReceivers != null) {
2305                    for (Receiver receiver : deadReceivers) {
2306                        removeUpdatesLocked(receiver);
2307                    }
2308                }
2309            }
2310        }
2311    };
2312
2313    // Geocoder
2314
2315    @Override
2316    public boolean geocoderIsPresent() {
2317        return mGeocodeProvider != null;
2318    }
2319
2320    @Override
2321    public String getFromLocation(double latitude, double longitude, int maxResults,
2322            GeocoderParams params, List<Address> addrs) {
2323        if (mGeocodeProvider != null) {
2324            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2325                    params, addrs);
2326        }
2327        return null;
2328    }
2329
2330
2331    @Override
2332    public String getFromLocationName(String locationName,
2333            double lowerLeftLatitude, double lowerLeftLongitude,
2334            double upperRightLatitude, double upperRightLongitude, int maxResults,
2335            GeocoderParams params, List<Address> addrs) {
2336
2337        if (mGeocodeProvider != null) {
2338            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2339                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2340                    maxResults, params, addrs);
2341        }
2342        return null;
2343    }
2344
2345    // Mock Providers
2346
2347    private void checkMockPermissionsSafe() {
2348        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2349                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2350        if (!allowMocks) {
2351            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2352        }
2353
2354        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2355                PackageManager.PERMISSION_GRANTED) {
2356            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
2357        }
2358    }
2359
2360    @Override
2361    public void addTestProvider(String name, ProviderProperties properties) {
2362        checkMockPermissionsSafe();
2363
2364        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2365            throw new IllegalArgumentException("Cannot mock the passive location provider");
2366        }
2367
2368        long identity = Binder.clearCallingIdentity();
2369        synchronized (mLock) {
2370            // remove the real provider if we are replacing GPS or network provider
2371            if (LocationManager.GPS_PROVIDER.equals(name)
2372                    || LocationManager.NETWORK_PROVIDER.equals(name)
2373                    || LocationManager.FUSED_PROVIDER.equals(name)) {
2374                LocationProviderInterface p = mProvidersByName.get(name);
2375                if (p != null) {
2376                    removeProviderLocked(p);
2377                }
2378            }
2379            addTestProviderLocked(name, properties);
2380            updateProvidersLocked();
2381        }
2382        Binder.restoreCallingIdentity(identity);
2383    }
2384
2385    private void addTestProviderLocked(String name, ProviderProperties properties) {
2386        if (mProvidersByName.get(name) != null) {
2387            throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2388        }
2389        MockProvider provider = new MockProvider(name, this, properties);
2390        addProviderLocked(provider);
2391        mMockProviders.put(name, provider);
2392        mLastLocation.put(name, null);
2393        mLastLocationCoarseInterval.put(name, null);
2394    }
2395
2396    @Override
2397    public void removeTestProvider(String provider) {
2398        checkMockPermissionsSafe();
2399        synchronized (mLock) {
2400
2401            // These methods can't be called after removing the test provider, so first make sure
2402            // we don't leave anything dangling.
2403            clearTestProviderEnabled(provider);
2404            clearTestProviderLocation(provider);
2405            clearTestProviderStatus(provider);
2406
2407            MockProvider mockProvider = mMockProviders.remove(provider);
2408            if (mockProvider == null) {
2409                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2410            }
2411            long identity = Binder.clearCallingIdentity();
2412            removeProviderLocked(mProvidersByName.get(provider));
2413
2414            // reinstate real provider if available
2415            LocationProviderInterface realProvider = mRealProviders.get(provider);
2416            if (realProvider != null) {
2417                addProviderLocked(realProvider);
2418            }
2419            mLastLocation.put(provider, null);
2420            mLastLocationCoarseInterval.put(provider, null);
2421            updateProvidersLocked();
2422            Binder.restoreCallingIdentity(identity);
2423        }
2424    }
2425
2426    @Override
2427    public void setTestProviderLocation(String provider, Location loc) {
2428        checkMockPermissionsSafe();
2429        synchronized (mLock) {
2430            MockProvider mockProvider = mMockProviders.get(provider);
2431            if (mockProvider == null) {
2432                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2433            }
2434            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2435            long identity = Binder.clearCallingIdentity();
2436            mockProvider.setLocation(loc);
2437            Binder.restoreCallingIdentity(identity);
2438        }
2439    }
2440
2441    @Override
2442    public void clearTestProviderLocation(String provider) {
2443        checkMockPermissionsSafe();
2444        synchronized (mLock) {
2445            MockProvider mockProvider = mMockProviders.get(provider);
2446            if (mockProvider == null) {
2447                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2448            }
2449            mockProvider.clearLocation();
2450        }
2451    }
2452
2453    @Override
2454    public void setTestProviderEnabled(String provider, boolean enabled) {
2455        checkMockPermissionsSafe();
2456        synchronized (mLock) {
2457            MockProvider mockProvider = mMockProviders.get(provider);
2458            if (mockProvider == null) {
2459                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2460            }
2461            long identity = Binder.clearCallingIdentity();
2462            if (enabled) {
2463                mockProvider.enable();
2464                mEnabledProviders.add(provider);
2465                mDisabledProviders.remove(provider);
2466            } else {
2467                mockProvider.disable();
2468                mEnabledProviders.remove(provider);
2469                mDisabledProviders.add(provider);
2470            }
2471            updateProvidersLocked();
2472            Binder.restoreCallingIdentity(identity);
2473        }
2474    }
2475
2476    @Override
2477    public void clearTestProviderEnabled(String provider) {
2478        checkMockPermissionsSafe();
2479        synchronized (mLock) {
2480            MockProvider mockProvider = mMockProviders.get(provider);
2481            if (mockProvider == null) {
2482                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2483            }
2484            long identity = Binder.clearCallingIdentity();
2485            mEnabledProviders.remove(provider);
2486            mDisabledProviders.remove(provider);
2487            updateProvidersLocked();
2488            Binder.restoreCallingIdentity(identity);
2489        }
2490    }
2491
2492    @Override
2493    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2494        checkMockPermissionsSafe();
2495        synchronized (mLock) {
2496            MockProvider mockProvider = mMockProviders.get(provider);
2497            if (mockProvider == null) {
2498                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2499            }
2500            mockProvider.setStatus(status, extras, updateTime);
2501        }
2502    }
2503
2504    @Override
2505    public void clearTestProviderStatus(String provider) {
2506        checkMockPermissionsSafe();
2507        synchronized (mLock) {
2508            MockProvider mockProvider = mMockProviders.get(provider);
2509            if (mockProvider == null) {
2510                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2511            }
2512            mockProvider.clearStatus();
2513        }
2514    }
2515
2516    private void log(String log) {
2517        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2518            Slog.d(TAG, log);
2519        }
2520    }
2521
2522    @Override
2523    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2524        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2525                != PackageManager.PERMISSION_GRANTED) {
2526            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2527                    + Binder.getCallingPid()
2528                    + ", uid=" + Binder.getCallingUid());
2529            return;
2530        }
2531
2532        synchronized (mLock) {
2533            pw.println("Current Location Manager state:");
2534            pw.println("  Location Listeners:");
2535            for (Receiver receiver : mReceivers.values()) {
2536                pw.println("    " + receiver);
2537            }
2538            pw.println("  Active Records by Provider:");
2539            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2540                pw.println("    " + entry.getKey() + ":");
2541                for (UpdateRecord record : entry.getValue()) {
2542                    pw.println("      " + record);
2543                }
2544            }
2545            pw.println("  Historical Records by Provider:");
2546            for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2547                    : mRequestStatistics.statistics.entrySet()) {
2548                PackageProviderKey key = entry.getKey();
2549                PackageStatistics stats = entry.getValue();
2550                pw.println("    " + key.packageName + ": " + key.providerName + ": " + stats);
2551            }
2552            pw.println("  Last Known Locations:");
2553            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2554                String provider = entry.getKey();
2555                Location location = entry.getValue();
2556                pw.println("    " + provider + ": " + location);
2557            }
2558
2559            pw.println("  Last Known Locations Coarse Intervals:");
2560            for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2561                String provider = entry.getKey();
2562                Location location = entry.getValue();
2563                pw.println("    " + provider + ": " + location);
2564            }
2565
2566            mGeofenceManager.dump(pw);
2567
2568            if (mEnabledProviders.size() > 0) {
2569                pw.println("  Enabled Providers:");
2570                for (String i : mEnabledProviders) {
2571                    pw.println("    " + i);
2572                }
2573
2574            }
2575            if (mDisabledProviders.size() > 0) {
2576                pw.println("  Disabled Providers:");
2577                for (String i : mDisabledProviders) {
2578                    pw.println("    " + i);
2579                }
2580            }
2581            pw.append("  ");
2582            mBlacklist.dump(pw);
2583            if (mMockProviders.size() > 0) {
2584                pw.println("  Mock Providers:");
2585                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2586                    i.getValue().dump(pw, "      ");
2587                }
2588            }
2589
2590            pw.append("  fudger: ");
2591            mLocationFudger.dump(fd, pw,  args);
2592
2593            if (args.length > 0 && "short".equals(args[0])) {
2594                return;
2595            }
2596            for (LocationProviderInterface provider: mProviders) {
2597                pw.print(provider.getName() + " Internal State");
2598                if (provider instanceof LocationProviderProxy) {
2599                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
2600                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
2601                }
2602                pw.println(":");
2603                provider.dump(fd, pw, args);
2604            }
2605        }
2606    }
2607}
2608