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