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