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