LocationManagerService.java revision c19efc204aee1f0f3164dc21bd2ef3fdd4259c71
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 android.app.PendingIntent;
20import android.content.BroadcastReceiver;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.content.pm.ApplicationInfo;
26import android.content.pm.PackageManager;
27import android.content.pm.PackageManager.NameNotFoundException;
28import android.content.res.Resources;
29import android.database.ContentObserver;
30import android.location.Address;
31import android.location.Criteria;
32import android.location.GeocoderParams;
33import android.location.Geofence;
34import android.location.IGpsStatusListener;
35import android.location.IGpsStatusProvider;
36import android.location.ILocationListener;
37import android.location.ILocationManager;
38import android.location.INetInitiatedListener;
39import android.location.Location;
40import android.location.LocationManager;
41import android.location.LocationProvider;
42import android.location.LocationRequest;
43import android.os.Binder;
44import android.os.Bundle;
45import android.os.Handler;
46import android.os.IBinder;
47import android.os.Looper;
48import android.os.Message;
49import android.os.PowerManager;
50import android.os.Process;
51import android.os.RemoteException;
52import android.os.SystemClock;
53import android.os.UserHandle;
54import android.os.WorkSource;
55import android.provider.Settings;
56import android.util.Log;
57import android.util.Slog;
58
59import com.android.internal.content.PackageMonitor;
60import com.android.internal.location.ProviderProperties;
61import com.android.internal.location.ProviderRequest;
62import com.android.server.location.GeocoderProxy;
63import com.android.server.location.GeofenceManager;
64import com.android.server.location.GpsLocationProvider;
65import com.android.server.location.LocationBlacklist;
66import com.android.server.location.LocationFudger;
67import com.android.server.location.LocationProviderInterface;
68import com.android.server.location.LocationProviderProxy;
69import com.android.server.location.MockProvider;
70import com.android.server.location.PassiveProvider;
71
72import java.io.FileDescriptor;
73import java.io.PrintWriter;
74import java.util.ArrayList;
75import java.util.Arrays;
76import java.util.HashMap;
77import java.util.HashSet;
78import java.util.List;
79import java.util.Map;
80import java.util.Set;
81
82/**
83 * The service class that manages LocationProviders and issues location
84 * updates and alerts.
85 */
86public class LocationManagerService extends ILocationManager.Stub implements Runnable {
87    private static final String TAG = "LocationManagerService";
88    public static final boolean D = false;
89
90    private static final String WAKELOCK_KEY = TAG;
91    private static final String THREAD_NAME = TAG;
92
93    private static final String ACCESS_FINE_LOCATION =
94            android.Manifest.permission.ACCESS_FINE_LOCATION;
95    private static final String ACCESS_COARSE_LOCATION =
96            android.Manifest.permission.ACCESS_COARSE_LOCATION;
97    private static final String ACCESS_MOCK_LOCATION =
98            android.Manifest.permission.ACCESS_MOCK_LOCATION;
99    private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
100            android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
101    private static final String INSTALL_LOCATION_PROVIDER =
102            android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
103
104    private static final String NETWORK_LOCATION_SERVICE_ACTION =
105            "com.android.location.service.v2.NetworkLocationProvider";
106    private static final String FUSED_LOCATION_SERVICE_ACTION =
107            "com.android.location.service.FusedLocationProvider";
108
109    private static final int MSG_LOCATION_CHANGED = 1;
110
111    // Location Providers may sometimes deliver location updates
112    // slightly faster that requested - provide grace period so
113    // we don't unnecessarily filter events that are otherwise on
114    // time
115    private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
116
117    private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
118
119    private final Context mContext;
120
121    // used internally for synchronization
122    private final Object mLock = new Object();
123
124    // --- fields below are final after init() ---
125    private LocationFudger mLocationFudger;
126    private GeofenceManager mGeofenceManager;
127    private PowerManager.WakeLock mWakeLock;
128    private PackageManager mPackageManager;
129    private GeocoderProxy mGeocodeProvider;
130    private IGpsStatusProvider mGpsStatusProvider;
131    private INetInitiatedListener mNetInitiatedListener;
132    private LocationWorkerHandler mLocationHandler;
133    private PassiveProvider mPassiveProvider;  // track passive provider for special cases
134    private LocationBlacklist mBlacklist;
135
136    // --- fields below are protected by mWakeLock ---
137    private int mPendingBroadcasts;
138
139    // --- fields below are protected by mLock ---
140    // Set of providers that are explicitly enabled
141    private final Set<String> mEnabledProviders = new HashSet<String>();
142
143    // Set of providers that are explicitly disabled
144    private final Set<String> mDisabledProviders = new HashSet<String>();
145
146    // Mock (test) providers
147    private final HashMap<String, MockProvider> mMockProviders =
148            new HashMap<String, MockProvider>();
149
150    // all receivers
151    private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
152
153    // currently installed providers (with mocks replacing real providers)
154    private final ArrayList<LocationProviderInterface> mProviders =
155            new ArrayList<LocationProviderInterface>();
156
157    // real providers, saved here when mocked out
158    private final HashMap<String, LocationProviderInterface> mRealProviders =
159            new HashMap<String, LocationProviderInterface>();
160
161    // mapping from provider name to provider
162    private final HashMap<String, LocationProviderInterface> mProvidersByName =
163            new HashMap<String, LocationProviderInterface>();
164
165    // mapping from provider name to all its UpdateRecords
166    private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
167            new HashMap<String, ArrayList<UpdateRecord>>();
168
169    // mapping from provider name to last known location
170    private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
171
172    // all providers that operate over proxy, for authorizing incoming location
173    private final ArrayList<LocationProviderProxy> mProxyProviders =
174            new ArrayList<LocationProviderProxy>();
175
176    // current active user on the device - other users are denied location data
177    private int mCurrentUserId = UserHandle.USER_OWNER;
178
179    public LocationManagerService(Context context) {
180        super();
181        mContext = context;
182
183        if (D) Log.d(TAG, "Constructed");
184
185        // most startup is deferred until systemReady()
186    }
187
188    public void systemReady() {
189        Thread thread = new Thread(null, this, THREAD_NAME);
190        thread.start();
191    }
192
193    @Override
194    public void run() {
195        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
196        Looper.prepare();
197        mLocationHandler = new LocationWorkerHandler();
198        init();
199        Looper.loop();
200    }
201
202    private void init() {
203        if (D) Log.d(TAG, "init()");
204
205        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
206        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
207        mPackageManager = mContext.getPackageManager();
208
209        mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
210        mBlacklist.init();
211        mLocationFudger = new LocationFudger(mContext, mLocationHandler);
212
213        synchronized (mLock) {
214            loadProvidersLocked();
215        }
216
217        mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
218
219        // listen for settings changes
220        mContext.getContentResolver().registerContentObserver(
221                Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
222                new ContentObserver(mLocationHandler) {
223           @Override
224            public void onChange(boolean selfChange) {
225               synchronized (mLock) {
226                   updateProvidersLocked();
227               }
228            }
229        });
230        mPackageMonitor.register(mContext, Looper.myLooper(), true);
231
232        // listen for user change
233        IntentFilter intentFilter = new IntentFilter();
234        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
235
236        mContext.registerReceiverAsUser(new BroadcastReceiver() {
237            @Override
238            public void onReceive(Context context, Intent intent) {
239                String action = intent.getAction();
240                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
241                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
242                }
243            }
244        }, UserHandle.ALL, intentFilter, null, null);
245
246        updateProvidersLocked();
247    }
248
249    private void loadProvidersLocked() {
250        // create a passive location provider, which is always enabled
251        PassiveProvider passiveProvider = new PassiveProvider(this);
252        addProviderLocked(passiveProvider);
253        mEnabledProviders.add(passiveProvider.getName());
254        mPassiveProvider = passiveProvider;
255
256        if (GpsLocationProvider.isSupported()) {
257            // Create a gps location provider
258            GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
259            mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
260            mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
261            addProviderLocked(gpsProvider);
262            mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
263        }
264
265        /*
266        Load package name(s) containing location provider support.
267        These packages can contain services implementing location providers:
268        Geocoder Provider, Network Location Provider, and
269        Fused Location Provider. They will each be searched for
270        service components implementing these providers.
271        The location framework also has support for installation
272        of new location providers at run-time. The new package does not
273        have to be explicitly listed here, however it must have a signature
274        that matches the signature of at least one package on this list.
275        */
276        Resources resources = mContext.getResources();
277        ArrayList<String> providerPackageNames = new ArrayList<String>();
278        String[] pkgs = resources.getStringArray(
279                com.android.internal.R.array.config_locationProviderPackageNames);
280        if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs));
281        if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
282
283        // bind to network provider
284        LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
285                mContext,
286                LocationManager.NETWORK_PROVIDER,
287                NETWORK_LOCATION_SERVICE_ACTION,
288                providerPackageNames, mLocationHandler);
289        if (networkProvider != null) {
290            mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
291            mProxyProviders.add(networkProvider);
292            addProviderLocked(networkProvider);
293        } else {
294            Slog.w(TAG,  "no network location provider found");
295        }
296
297        // bind to fused provider
298        LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
299                mContext,
300                LocationManager.FUSED_PROVIDER,
301                FUSED_LOCATION_SERVICE_ACTION,
302                providerPackageNames, mLocationHandler);
303        if (fusedLocationProvider != null) {
304            addProviderLocked(fusedLocationProvider);
305            mProxyProviders.add(fusedLocationProvider);
306            mEnabledProviders.add(fusedLocationProvider.getName());
307        } else {
308            Slog.e(TAG, "no fused location provider found",
309                    new IllegalStateException("Location service needs a fused location provider"));
310        }
311
312        // bind to geocoder provider
313        mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
314        if (mGeocodeProvider == null) {
315            Slog.e(TAG,  "no geocoder provider found");
316        }
317    }
318
319    /**
320     * Called when the device's active user changes.
321     * @param userId the new active user's UserId
322     */
323    private void switchUser(int userId) {
324        //Log.d("LocationManagerService", "switchUser(" + mCurrentUserId + " -> " + userId + ")"); // TODO: remove this
325        synchronized (mLock) {
326            // TODO: inform previous user's Receivers that they will no longer receive updates
327            mCurrentUserId = userId;
328            // TODO: inform new user's Receivers that they are back on the update train
329        }
330    }
331
332    /**
333     * A wrapper class holding either an ILocationListener or a PendingIntent to receive
334     * location updates.
335     */
336    private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
337        final int mUid;  // uid of receiver
338        final int mPid;  // pid of receiver
339        final String mPackageName;  // package name of receiver
340        final String mPermission;  // best permission that receiver has
341
342        final ILocationListener mListener;
343        final PendingIntent mPendingIntent;
344        final Object mKey;
345
346        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
347
348        int mPendingBroadcasts;
349
350        Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
351                String packageName) {
352            mListener = listener;
353            mPendingIntent = intent;
354            if (listener != null) {
355                mKey = listener.asBinder();
356            } else {
357                mKey = intent;
358            }
359            mPermission = checkPermission();
360            mUid = uid;
361            mPid = pid;
362            mPackageName = packageName;
363        }
364
365        @Override
366        public boolean equals(Object otherObj) {
367            if (otherObj instanceof Receiver) {
368                return mKey.equals(((Receiver)otherObj).mKey);
369            }
370            return false;
371        }
372
373        @Override
374        public int hashCode() {
375            return mKey.hashCode();
376        }
377
378        @Override
379        public String toString() {
380            StringBuilder s = new StringBuilder();
381            s.append("Reciever[");
382            s.append(Integer.toHexString(System.identityHashCode(this)));
383            if (mListener != null) {
384                s.append(" listener");
385            } else {
386                s.append(" intent");
387            }
388            for (String p : mUpdateRecords.keySet()) {
389                s.append(" ").append(mUpdateRecords.get(p).toString());
390            }
391            s.append("]");
392            return s.toString();
393        }
394
395        public boolean isListener() {
396            return mListener != null;
397        }
398
399        public boolean isPendingIntent() {
400            return mPendingIntent != null;
401        }
402
403        public ILocationListener getListener() {
404            if (mListener != null) {
405                return mListener;
406            }
407            throw new IllegalStateException("Request for non-existent listener");
408        }
409
410        public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
411            if (mListener != null) {
412                try {
413                    synchronized (this) {
414                        // synchronize to ensure incrementPendingBroadcastsLocked()
415                        // is called before decrementPendingBroadcasts()
416                        mListener.onStatusChanged(provider, status, extras);
417                        // call this after broadcasting so we do not increment
418                        // if we throw an exeption.
419                        incrementPendingBroadcastsLocked();
420                    }
421                } catch (RemoteException e) {
422                    return false;
423                }
424            } else {
425                Intent statusChanged = new Intent();
426                statusChanged.putExtras(extras);
427                statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
428                try {
429                    synchronized (this) {
430                        // synchronize to ensure incrementPendingBroadcastsLocked()
431                        // is called before decrementPendingBroadcasts()
432                        mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
433                                mPermission);
434                        // call this after broadcasting so we do not increment
435                        // if we throw an exeption.
436                        incrementPendingBroadcastsLocked();
437                    }
438                } catch (PendingIntent.CanceledException e) {
439                    return false;
440                }
441            }
442            return true;
443        }
444
445        public boolean callLocationChangedLocked(Location location) {
446            if (mListener != null) {
447                try {
448                    synchronized (this) {
449                        // synchronize to ensure incrementPendingBroadcastsLocked()
450                        // is called before decrementPendingBroadcasts()
451                        mListener.onLocationChanged(location);
452                        // call this after broadcasting so we do not increment
453                        // if we throw an exeption.
454                        incrementPendingBroadcastsLocked();
455                    }
456                } catch (RemoteException e) {
457                    return false;
458                }
459            } else {
460                Intent locationChanged = new Intent();
461                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
462                try {
463                    synchronized (this) {
464                        // synchronize to ensure incrementPendingBroadcastsLocked()
465                        // is called before decrementPendingBroadcasts()
466                        mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
467                                mPermission);
468                        // call this after broadcasting so we do not increment
469                        // if we throw an exeption.
470                        incrementPendingBroadcastsLocked();
471                    }
472                } catch (PendingIntent.CanceledException e) {
473                    return false;
474                }
475            }
476            return true;
477        }
478
479        public boolean callProviderEnabledLocked(String provider, boolean enabled) {
480            if (mListener != null) {
481                try {
482                    synchronized (this) {
483                        // synchronize to ensure incrementPendingBroadcastsLocked()
484                        // is called before decrementPendingBroadcasts()
485                        if (enabled) {
486                            mListener.onProviderEnabled(provider);
487                        } else {
488                            mListener.onProviderDisabled(provider);
489                        }
490                        // call this after broadcasting so we do not increment
491                        // if we throw an exeption.
492                        incrementPendingBroadcastsLocked();
493                    }
494                } catch (RemoteException e) {
495                    return false;
496                }
497            } else {
498                Intent providerIntent = new Intent();
499                providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
500                try {
501                    synchronized (this) {
502                        // synchronize to ensure incrementPendingBroadcastsLocked()
503                        // is called before decrementPendingBroadcasts()
504                        mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
505                                mPermission);
506                        // call this after broadcasting so we do not increment
507                        // if we throw an exeption.
508                        incrementPendingBroadcastsLocked();
509                    }
510                } catch (PendingIntent.CanceledException e) {
511                    return false;
512                }
513            }
514            return true;
515        }
516
517        @Override
518        public void binderDied() {
519            if (D) Log.d(TAG, "Location listener died");
520
521            synchronized (mLock) {
522                removeUpdatesLocked(this);
523            }
524            synchronized (this) {
525                if (mPendingBroadcasts > 0) {
526                    LocationManagerService.this.decrementPendingBroadcasts();
527                    mPendingBroadcasts = 0;
528                }
529            }
530        }
531
532        @Override
533        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
534                int resultCode, String resultData, Bundle resultExtras) {
535            synchronized (this) {
536                decrementPendingBroadcastsLocked();
537            }
538        }
539
540        // this must be called while synchronized by caller in a synchronized block
541        // containing the sending of the broadcaset
542        private void incrementPendingBroadcastsLocked() {
543            if (mPendingBroadcasts++ == 0) {
544                LocationManagerService.this.incrementPendingBroadcasts();
545            }
546        }
547
548        private void decrementPendingBroadcastsLocked() {
549            if (--mPendingBroadcasts == 0) {
550                LocationManagerService.this.decrementPendingBroadcasts();
551            }
552        }
553    }
554
555    @Override
556    public void locationCallbackFinished(ILocationListener listener) {
557        //Do not use getReceiver here as that will add the ILocationListener to
558        //the receiver list if it is not found.  If it is not found then the
559        //LocationListener was removed when it had a pending broadcast and should
560        //not be added back.
561        IBinder binder = listener.asBinder();
562        Receiver receiver = mReceivers.get(binder);
563        if (receiver != null) {
564            synchronized (receiver) {
565                // so wakelock calls will succeed
566                long identity = Binder.clearCallingIdentity();
567                receiver.decrementPendingBroadcastsLocked();
568                Binder.restoreCallingIdentity(identity);
569           }
570        }
571    }
572
573    private void addProviderLocked(LocationProviderInterface provider) {
574        mProviders.add(provider);
575        mProvidersByName.put(provider.getName(), provider);
576    }
577
578    private void removeProviderLocked(LocationProviderInterface provider) {
579        provider.disable();
580        mProviders.remove(provider);
581        mProvidersByName.remove(provider.getName());
582    }
583
584
585    private boolean isAllowedBySettingsLocked(String provider) {
586        if (mEnabledProviders.contains(provider)) {
587            return true;
588        }
589        if (mDisabledProviders.contains(provider)) {
590            return false;
591        }
592        // Use system settings
593        ContentResolver resolver = mContext.getContentResolver();
594
595        return Settings.Secure.isLocationProviderEnabled(resolver, provider);
596    }
597
598    /**
599     * Throw SecurityException if caller has neither COARSE or FINE.
600     * Otherwise, return the best permission.
601     */
602    private String checkPermission() {
603        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
604                PackageManager.PERMISSION_GRANTED) {
605            return ACCESS_FINE_LOCATION;
606        } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
607                PackageManager.PERMISSION_GRANTED) {
608            return ACCESS_COARSE_LOCATION;
609        }
610
611        throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
612                " ACCESS_FINE_LOCATION permission");
613    }
614
615    /**
616     * Throw SecurityException if caller lacks permission to use Geofences.
617     */
618    private void checkGeofencePermission() {
619        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
620                PackageManager.PERMISSION_GRANTED) {
621            throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
622        }
623    }
624
625    private boolean isAllowedProviderSafe(String provider) {
626        if (LocationManager.GPS_PROVIDER.equals(provider) ||
627                LocationManager.PASSIVE_PROVIDER.equals(provider)) {
628            // gps and passive providers require FINE permission
629            return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
630                    == PackageManager.PERMISSION_GRANTED;
631        } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
632                LocationManager.FUSED_PROVIDER.equals(provider)) {
633            // network and fused providers are ok with COARSE or FINE
634            return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
635                    == PackageManager.PERMISSION_GRANTED) ||
636                    (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
637                    == PackageManager.PERMISSION_GRANTED);
638        }
639        return false;
640    }
641
642    /**
643     * Returns all providers by name, including passive, but excluding
644     * fused, also including ones that are not permitted to
645     * be accessed by the calling activity or are currently disabled.
646     */
647    @Override
648    public List<String> getAllProviders() {
649        ArrayList<String> out;
650        synchronized (mLock) {
651            out = new ArrayList<String>(mProviders.size());
652            for (LocationProviderInterface provider : mProviders) {
653                String name = provider.getName();
654                if (LocationManager.FUSED_PROVIDER.equals(name)) {
655                    continue;
656                }
657                out.add(name);
658            }
659        }
660
661        if (D) Log.d(TAG, "getAllProviders()=" + out);
662        return out;
663    }
664
665    /**
666     * Return all providers by name, that match criteria and are optionally
667     * enabled.
668     * Can return passive provider, but never returns fused provider.
669     */
670    @Override
671    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
672        ArrayList<String> out;
673        synchronized (mLock) {
674            out = new ArrayList<String>(mProviders.size());
675            for (LocationProviderInterface provider : mProviders) {
676                String name = provider.getName();
677                if (LocationManager.FUSED_PROVIDER.equals(name)) {
678                    continue;
679                }
680                if (isAllowedProviderSafe(name)) {
681                    if (enabledOnly && !isAllowedBySettingsLocked(name)) {
682                        continue;
683                    }
684                    if (criteria != null && !LocationProvider.propertiesMeetCriteria(
685                            name, provider.getProperties(), criteria)) {
686                        continue;
687                    }
688                    out.add(name);
689                }
690            }
691        }
692
693        if (D) Log.d(TAG, "getProviders()=" + out);
694        return out;
695    }
696
697    /**
698     * Return the name of the best provider given a Criteria object.
699     * This method has been deprecated from the public API,
700     * and the whole LocationProvider (including #meetsCriteria)
701     * has been deprecated as well. So this method now uses
702     * some simplified logic.
703     */
704    @Override
705    public String getBestProvider(Criteria criteria, boolean enabledOnly) {
706        String result = null;
707
708        List<String> providers = getProviders(criteria, enabledOnly);
709        if (!providers.isEmpty()) {
710            result = pickBest(providers);
711            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
712            return result;
713        }
714        providers = getProviders(null, enabledOnly);
715        if (!providers.isEmpty()) {
716            result = pickBest(providers);
717            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
718            return result;
719        }
720
721        if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
722        return null;
723    }
724
725    private String pickBest(List<String> providers) {
726        if (providers.contains(LocationManager.GPS_PROVIDER)) {
727            return LocationManager.GPS_PROVIDER;
728        } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
729            return LocationManager.NETWORK_PROVIDER;
730        } else {
731            return providers.get(0);
732        }
733    }
734
735    @Override
736    public boolean providerMeetsCriteria(String provider, Criteria criteria) {
737        checkPermission();
738
739        LocationProviderInterface p = mProvidersByName.get(provider);
740        if (p == null) {
741            throw new IllegalArgumentException("provider=" + provider);
742        }
743
744        boolean result = LocationProvider.propertiesMeetCriteria(
745                p.getName(), p.getProperties(), criteria);
746        if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
747        return result;
748    }
749
750    private void updateProvidersLocked() {
751        boolean changesMade = false;
752        for (int i = mProviders.size() - 1; i >= 0; i--) {
753            LocationProviderInterface p = mProviders.get(i);
754            boolean isEnabled = p.isEnabled();
755            String name = p.getName();
756            boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
757            if (isEnabled && !shouldBeEnabled) {
758                updateProviderListenersLocked(name, false);
759                changesMade = true;
760            } else if (!isEnabled && shouldBeEnabled) {
761                updateProviderListenersLocked(name, true);
762                changesMade = true;
763            }
764        }
765        if (changesMade) {
766            mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
767                    UserHandle.ALL);
768        }
769    }
770
771    private void updateProviderListenersLocked(String provider, boolean enabled) {
772        int listeners = 0;
773
774        LocationProviderInterface p = mProvidersByName.get(provider);
775        if (p == null) return;
776
777        ArrayList<Receiver> deadReceivers = null;
778
779        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
780        if (records != null) {
781            final int N = records.size();
782            for (int i = 0; i < N; i++) {
783                UpdateRecord record = records.get(i);
784                // Sends a notification message to the receiver
785                if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
786                    if (deadReceivers == null) {
787                        deadReceivers = new ArrayList<Receiver>();
788                    }
789                    deadReceivers.add(record.mReceiver);
790                }
791                listeners++;
792            }
793        }
794
795        if (deadReceivers != null) {
796            for (int i = deadReceivers.size() - 1; i >= 0; i--) {
797                removeUpdatesLocked(deadReceivers.get(i));
798            }
799        }
800
801        if (enabled) {
802            p.enable();
803            if (listeners > 0) {
804                applyRequirementsLocked(provider);
805            }
806        } else {
807            p.disable();
808        }
809    }
810
811    private void applyRequirementsLocked(String provider) {
812        LocationProviderInterface p = mProvidersByName.get(provider);
813        if (p == null) return;
814
815        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
816        WorkSource worksource = new WorkSource();
817        ProviderRequest providerRequest = new ProviderRequest();
818
819        if (records != null) {
820            for (UpdateRecord record : records) {
821                LocationRequest locationRequest = record.mRequest;
822
823                providerRequest.locationRequests.add(locationRequest);
824                if (locationRequest.getInterval() < providerRequest.interval) {
825                    providerRequest.reportLocation = true;
826                    providerRequest.interval = locationRequest.getInterval();
827                }
828            }
829
830            if (providerRequest.reportLocation) {
831                // calculate who to blame for power
832                // This is somewhat arbitrary. We pick a threshold interval
833                // that is slightly higher that the minimum interval, and
834                // spread the blame across all applications with a request
835                // under that threshold.
836                long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
837                for (UpdateRecord record : records) {
838                    LocationRequest locationRequest = record.mRequest;
839                    if (locationRequest.getInterval() <= thresholdInterval) {
840                        worksource.add(record.mReceiver.mUid);
841                    }
842                }
843            }
844        }
845
846        if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
847        p.setRequest(providerRequest, worksource);
848    }
849
850    private class UpdateRecord {
851        final String mProvider;
852        final LocationRequest mRequest;
853        final Receiver mReceiver;
854        Location mLastFixBroadcast;
855        long mLastStatusBroadcast;
856
857        /**
858         * Note: must be constructed with lock held.
859         */
860        UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
861            mProvider = provider;
862            mRequest = request;
863            mReceiver = receiver;
864
865            ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
866            if (records == null) {
867                records = new ArrayList<UpdateRecord>();
868                mRecordsByProvider.put(provider, records);
869            }
870            if (!records.contains(this)) {
871                records.add(this);
872            }
873        }
874
875        /**
876         * Method to be called when a record will no longer be used.  Calling this multiple times
877         * must have the same effect as calling it once.
878         */
879        void disposeLocked(boolean removeReceiver) {
880            // remove from mRecordsByProvider
881            ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
882            if (globalRecords != null) {
883                globalRecords.remove(this);
884            }
885
886            if (!removeReceiver) return;  // the caller will handle the rest
887
888            // remove from Receiver#mUpdateRecords
889            HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
890            if (receiverRecords != null) {
891                receiverRecords.remove(this.mProvider);
892
893                // and also remove the Receiver if it has no more update records
894                if (removeReceiver && receiverRecords.size() == 0) {
895                    removeUpdatesLocked(mReceiver);
896                }
897            }
898        }
899
900        @Override
901        public String toString() {
902            StringBuilder s = new StringBuilder();
903            s.append("UpdateRecord[");
904            s.append(mProvider);
905            s.append(' ').append(mReceiver.mPackageName).append('(');
906            s.append(mReceiver.mUid).append(')');
907            s.append(' ').append(mRequest);
908            s.append(']');
909            return s.toString();
910        }
911    }
912
913    private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
914        IBinder binder = listener.asBinder();
915        Receiver receiver = mReceivers.get(binder);
916        if (receiver == null) {
917            receiver = new Receiver(listener, null, pid, uid, packageName);
918            mReceivers.put(binder, receiver);
919
920            try {
921                receiver.getListener().asBinder().linkToDeath(receiver, 0);
922            } catch (RemoteException e) {
923                Slog.e(TAG, "linkToDeath failed:", e);
924                return null;
925            }
926        }
927        return receiver;
928    }
929
930    private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
931        Receiver receiver = mReceivers.get(intent);
932        if (receiver == null) {
933            receiver = new Receiver(null, intent, pid, uid, packageName);
934            mReceivers.put(intent, receiver);
935        }
936        return receiver;
937    }
938
939    private boolean isProviderAllowedByCoarsePermission(String provider) {
940        if (LocationManager.FUSED_PROVIDER.equals(provider)) {
941            return true;
942        }
943        if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
944            return true;
945        }
946        if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
947            return true;
948        }
949        return false;
950    }
951
952    private String checkPermissionAndRequest(LocationRequest request) {
953        String perm = checkPermission();
954
955        if (ACCESS_COARSE_LOCATION.equals(perm)) {
956            if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
957                throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
958            }
959            switch (request.getQuality()) {
960                case LocationRequest.ACCURACY_FINE:
961                    request.setQuality(LocationRequest.ACCURACY_BLOCK);
962                    break;
963                case LocationRequest.POWER_HIGH:
964                    request.setQuality(LocationRequest.POWER_LOW);
965                    break;
966            }
967            // throttle
968            if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
969                request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
970            }
971            if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
972                request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
973            }
974        }
975        // make getFastestInterval() the minimum of interval and fastest interval
976        if (request.getFastestInterval() > request.getInterval()) {
977            request.setFastestInterval(request.getInterval());
978        }
979        return perm;
980    }
981
982    private void checkPackageName(String packageName) {
983        if (packageName == null) {
984            throw new SecurityException("invalid package name: " + packageName);
985        }
986        int uid = Binder.getCallingUid();
987        String[] packages = mPackageManager.getPackagesForUid(uid);
988        if (packages == null) {
989            throw new SecurityException("invalid UID " + uid);
990        }
991        for (String pkg : packages) {
992            if (packageName.equals(pkg)) return;
993        }
994        throw new SecurityException("invalid package name: " + packageName);
995    }
996
997    private void checkPendingIntent(PendingIntent intent) {
998        if (intent == null) {
999            throw new IllegalArgumentException("invalid pending intent: " + intent);
1000        }
1001    }
1002
1003    private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1004            int pid, int uid, String packageName) {
1005        if (intent == null && listener == null) {
1006            throw new IllegalArgumentException("need eiter listener or intent");
1007        } else if (intent != null && listener != null) {
1008            throw new IllegalArgumentException("cannot register both listener and intent");
1009        } else if (intent != null) {
1010            checkPendingIntent(intent);
1011            return getReceiver(intent, pid, uid, packageName);
1012        } else {
1013            return getReceiver(listener, pid, uid, packageName);
1014        }
1015    }
1016
1017    @Override
1018    public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1019            PendingIntent intent, String packageName) {
1020        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1021        checkPackageName(packageName);
1022        checkPermissionAndRequest(request);
1023
1024        final int pid = Binder.getCallingPid();
1025        final int uid = Binder.getCallingUid();
1026        Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1027
1028        // providers may use public location API's, need to clear identity
1029        long identity = Binder.clearCallingIdentity();
1030        try {
1031            synchronized (mLock) {
1032                requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
1033            }
1034        } finally {
1035            Binder.restoreCallingIdentity(identity);
1036        }
1037    }
1038
1039    private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1040            int pid, int uid, String packageName) {
1041        // Figure out the provider. Either its explicitly request (legacy use cases), or
1042        // use the fused provider
1043        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1044        String name = request.getProvider();
1045        if (name == null) {
1046            throw new IllegalArgumentException("provider name must not be null");
1047        }
1048        LocationProviderInterface provider = mProvidersByName.get(name);
1049        if (provider == null) {
1050            throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1051        }
1052
1053        Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1054                name + " " + request + " from " + packageName + "(" + uid + ")");
1055
1056        UpdateRecord record = new UpdateRecord(name, request, receiver);
1057        UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1058        if (oldRecord != null) {
1059            oldRecord.disposeLocked(false);
1060        }
1061
1062        boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1063        if (isProviderEnabled) {
1064            applyRequirementsLocked(name);
1065        } else {
1066            // Notify the listener that updates are currently disabled
1067            receiver.callProviderEnabledLocked(name, false);
1068        }
1069    }
1070
1071    @Override
1072    public void removeUpdates(ILocationListener listener, PendingIntent intent,
1073            String packageName) {
1074        checkPackageName(packageName);
1075        checkPermission();
1076        final int pid = Binder.getCallingPid();
1077        final int uid = Binder.getCallingUid();
1078        Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1079
1080        // providers may use public location API's, need to clear identity
1081        long identity = Binder.clearCallingIdentity();
1082        try {
1083            synchronized (mLock) {
1084                removeUpdatesLocked(receiver);
1085            }
1086        } finally {
1087            Binder.restoreCallingIdentity(identity);
1088        }
1089    }
1090
1091    private void removeUpdatesLocked(Receiver receiver) {
1092        Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1093
1094        if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1095            receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1096            synchronized (receiver) {
1097                if (receiver.mPendingBroadcasts > 0) {
1098                    decrementPendingBroadcasts();
1099                    receiver.mPendingBroadcasts = 0;
1100                }
1101            }
1102        }
1103
1104        // Record which providers were associated with this listener
1105        HashSet<String> providers = new HashSet<String>();
1106        HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1107        if (oldRecords != null) {
1108            // Call dispose() on the obsolete update records.
1109            for (UpdateRecord record : oldRecords.values()) {
1110                record.disposeLocked(false);
1111            }
1112            // Accumulate providers
1113            providers.addAll(oldRecords.keySet());
1114        }
1115
1116        // update provider
1117        for (String provider : providers) {
1118            // If provider is already disabled, don't need to do anything
1119            if (!isAllowedBySettingsLocked(provider)) {
1120                continue;
1121            }
1122
1123            applyRequirementsLocked(provider);
1124        }
1125    }
1126
1127    @Override
1128    public Location getLastLocation(LocationRequest request, String packageName) {
1129        if (D) Log.d(TAG, "getLastLocation: " + request);
1130        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1131        String perm = checkPermissionAndRequest(request);
1132        checkPackageName(packageName);
1133
1134        if (mBlacklist.isBlacklisted(packageName)) {
1135            if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1136                    packageName);
1137            return null;
1138        }
1139
1140        synchronized (mLock) {
1141            // Figure out the provider. Either its explicitly request (deprecated API's),
1142            // or use the fused provider
1143            String name = request.getProvider();
1144            if (name == null) name = LocationManager.FUSED_PROVIDER;
1145            LocationProviderInterface provider = mProvidersByName.get(name);
1146            if (provider == null) return null;
1147
1148            if (!isAllowedBySettingsLocked(name)) return null;
1149
1150            Location location = mLastLocation.get(name);
1151            if (location == null) {
1152                return null;
1153            }
1154            if (ACCESS_FINE_LOCATION.equals(perm)) {
1155                return location;
1156            } else {
1157                Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1158                if (noGPSLocation != null) {
1159                    return mLocationFudger.getOrCreate(noGPSLocation);
1160                }
1161            }
1162        }
1163        return null;
1164    }
1165
1166    @Override
1167    public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1168            String packageName) {
1169        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1170        checkGeofencePermission();
1171        checkPermissionAndRequest(request);
1172        checkPendingIntent(intent);
1173        checkPackageName(packageName);
1174
1175        if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1176
1177        // geo-fence manager uses the public location API, need to clear identity
1178        int uid = Binder.getCallingUid();
1179        long identity = Binder.clearCallingIdentity();
1180        try {
1181            mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1182        } finally {
1183            Binder.restoreCallingIdentity(identity);
1184        }
1185    }
1186
1187    @Override
1188    public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1189        checkGeofencePermission();
1190        checkPendingIntent(intent);
1191        checkPackageName(packageName);
1192
1193        if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1194
1195        // geo-fence manager uses the public location API, need to clear identity
1196        long identity = Binder.clearCallingIdentity();
1197        try {
1198            mGeofenceManager.removeFence(geofence, intent);
1199        } finally {
1200            Binder.restoreCallingIdentity(identity);
1201        }
1202    }
1203
1204
1205    @Override
1206    public boolean addGpsStatusListener(IGpsStatusListener listener) {
1207        if (mGpsStatusProvider == null) {
1208            return false;
1209        }
1210        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
1211                PackageManager.PERMISSION_GRANTED) {
1212            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1213        }
1214
1215        try {
1216            mGpsStatusProvider.addGpsStatusListener(listener);
1217        } catch (RemoteException e) {
1218            Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
1219            return false;
1220        }
1221        return true;
1222    }
1223
1224    @Override
1225    public void removeGpsStatusListener(IGpsStatusListener listener) {
1226        synchronized (mLock) {
1227            try {
1228                mGpsStatusProvider.removeGpsStatusListener(listener);
1229            } catch (Exception e) {
1230                Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1231            }
1232        }
1233    }
1234
1235    @Override
1236    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1237        if (provider == null) {
1238            // throw NullPointerException to remain compatible with previous implementation
1239            throw new NullPointerException();
1240        }
1241
1242        checkPermission();
1243        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1244        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1245                != PackageManager.PERMISSION_GRANTED)) {
1246            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1247        }
1248
1249        synchronized (mLock) {
1250            LocationProviderInterface p = mProvidersByName.get(provider);
1251            if (p == null) return false;
1252
1253            return p.sendExtraCommand(command, extras);
1254        }
1255    }
1256
1257    @Override
1258    public boolean sendNiResponse(int notifId, int userResponse) {
1259        if (Binder.getCallingUid() != Process.myUid()) {
1260            throw new SecurityException(
1261                    "calling sendNiResponse from outside of the system is not allowed");
1262        }
1263        try {
1264            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1265        } catch (RemoteException e) {
1266            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1267            return false;
1268        }
1269    }
1270
1271    /**
1272     * @return null if the provider does not exist
1273     * @throws SecurityException if the provider is not allowed to be
1274     * accessed by the caller
1275     */
1276    @Override
1277    public ProviderProperties getProviderProperties(String provider) {
1278        checkPermission();
1279
1280        LocationProviderInterface p;
1281        synchronized (mLock) {
1282            p = mProvidersByName.get(provider);
1283        }
1284
1285        if (p == null) return null;
1286        return p.getProperties();
1287    }
1288
1289    @Override
1290    public boolean isProviderEnabled(String provider) {
1291        checkPermission();
1292        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1293
1294        synchronized (mLock) {
1295            LocationProviderInterface p = mProvidersByName.get(provider);
1296            if (p == null) return false;
1297
1298            return isAllowedBySettingsLocked(provider);
1299        }
1300    }
1301
1302    private void checkCallerIsProvider() {
1303        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1304                == PackageManager.PERMISSION_GRANTED) {
1305            return;
1306        }
1307
1308        // Previously we only used the INSTALL_LOCATION_PROVIDER
1309        // check. But that is system or signature
1310        // protection level which is not flexible enough for
1311        // providers installed oustide the system image. So
1312        // also allow providers with a UID matching the
1313        // currently bound package name
1314
1315        int uid = Binder.getCallingUid();
1316
1317        if (mGeocodeProvider != null) {
1318            if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1319        }
1320        for (LocationProviderProxy proxy : mProxyProviders) {
1321            if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1322        }
1323        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1324                "or UID of a currently bound location provider");
1325    }
1326
1327    private boolean doesPackageHaveUid(int uid, String packageName) {
1328        if (packageName == null) {
1329            return false;
1330        }
1331        try {
1332            ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1333            if (appInfo.uid != uid) {
1334                return false;
1335            }
1336        } catch (NameNotFoundException e) {
1337            return false;
1338        }
1339        return true;
1340    }
1341
1342    @Override
1343    public void reportLocation(Location location, boolean passive) {
1344        checkCallerIsProvider();
1345
1346        if (!location.isComplete()) {
1347            Log.w(TAG, "Dropping incomplete location: " + location);
1348            return;
1349        }
1350
1351        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1352        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
1353        m.arg1 = (passive ? 1 : 0);
1354        mLocationHandler.sendMessageAtFrontOfQueue(m);
1355    }
1356
1357
1358    private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1359        // Always broadcast the first update
1360        if (lastLoc == null) {
1361            return true;
1362        }
1363
1364        // Check whether sufficient time has passed
1365        long minTime = record.mRequest.getFastestInterval();
1366        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
1367        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
1368            return false;
1369        }
1370
1371        // Check whether sufficient distance has been traveled
1372        double minDistance = record.mRequest.getSmallestDisplacement();
1373        if (minDistance > 0.0) {
1374            if (loc.distanceTo(lastLoc) <= minDistance) {
1375                return false;
1376            }
1377        }
1378
1379        return true;
1380    }
1381
1382    private void handleLocationChangedLocked(Location location, boolean passive) {
1383        if (D) Log.d(TAG, "incoming location: " + location);
1384
1385        long now = SystemClock.elapsedRealtime();
1386        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
1387        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1388        if (records == null || records.size() == 0) return;
1389
1390        LocationProviderInterface p = mProvidersByName.get(provider);
1391        if (p == null) return;
1392
1393        // Update last known locations
1394        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1395        Location lastNoGPSLocation = null;
1396        Location lastLocation = mLastLocation.get(provider);
1397        if (lastLocation == null) {
1398            lastLocation = new Location(provider);
1399            mLastLocation.put(provider, lastLocation);
1400        } else {
1401            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1402            if (noGPSLocation == null && lastNoGPSLocation != null) {
1403                // New location has no no-GPS location: adopt last no-GPS location. This is set
1404                // directly into location because we do not want to notify COARSE clients.
1405                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1406            }
1407        }
1408        lastLocation.set(location);
1409
1410        // Fetch coarse location
1411        Location coarseLocation = null;
1412        if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1413            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1414        }
1415
1416        // Fetch latest status update time
1417        long newStatusUpdateTime = p.getStatusUpdateTime();
1418
1419       // Get latest status
1420        Bundle extras = new Bundle();
1421        int status = p.getStatus(extras);
1422
1423        ArrayList<Receiver> deadReceivers = null;
1424        ArrayList<UpdateRecord> deadUpdateRecords = null;
1425
1426        // Broadcast location or status to all listeners
1427        for (UpdateRecord r : records) {
1428            Receiver receiver = r.mReceiver;
1429            boolean receiverDead = false;
1430
1431            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1432                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1433                        receiver.mPackageName);
1434                continue;
1435            }
1436
1437            Location notifyLocation = null;
1438            if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1439                notifyLocation = lastLocation;  // use fine location
1440            } else {
1441                notifyLocation = coarseLocation;  // use coarse location if available
1442            }
1443            if (notifyLocation != null) {
1444                Location lastLoc = r.mLastFixBroadcast;
1445                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1446                    if (lastLoc == null) {
1447                        lastLoc = new Location(notifyLocation);
1448                        r.mLastFixBroadcast = lastLoc;
1449                    } else {
1450                        lastLoc.set(notifyLocation);
1451                    }
1452                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
1453                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1454                        receiverDead = true;
1455                    }
1456                }
1457            }
1458
1459            long prevStatusUpdateTime = r.mLastStatusBroadcast;
1460            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1461                    (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1462
1463                r.mLastStatusBroadcast = newStatusUpdateTime;
1464                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1465                    receiverDead = true;
1466                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1467                }
1468            }
1469
1470            // track expired records
1471            if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1472                if (deadUpdateRecords == null) {
1473                    deadUpdateRecords = new ArrayList<UpdateRecord>();
1474                }
1475                deadUpdateRecords.add(r);
1476            }
1477            // track dead receivers
1478            if (receiverDead) {
1479                if (deadReceivers == null) {
1480                    deadReceivers = new ArrayList<Receiver>();
1481                }
1482                if (!deadReceivers.contains(receiver)) {
1483                    deadReceivers.add(receiver);
1484                }
1485            }
1486        }
1487
1488        // remove dead records and receivers outside the loop
1489        if (deadReceivers != null) {
1490            for (Receiver receiver : deadReceivers) {
1491                removeUpdatesLocked(receiver);
1492            }
1493        }
1494        if (deadUpdateRecords != null) {
1495            for (UpdateRecord r : deadUpdateRecords) {
1496                r.disposeLocked(true);
1497            }
1498        }
1499    }
1500
1501    private class LocationWorkerHandler extends Handler {
1502        @Override
1503        public void handleMessage(Message msg) {
1504            switch (msg.what) {
1505                case MSG_LOCATION_CHANGED:
1506                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1507                    break;
1508            }
1509        }
1510    }
1511
1512    private void handleLocationChanged(Location location, boolean passive) {
1513        String provider = location.getProvider();
1514
1515        if (!passive) {
1516            // notify passive provider of the new location
1517            mPassiveProvider.updateLocation(location);
1518        }
1519
1520        synchronized (mLock) {
1521            if (isAllowedBySettingsLocked(provider)) {
1522                handleLocationChangedLocked(location, passive);
1523            }
1524        }
1525    }
1526
1527    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1528        @Override
1529        public void onPackageDisappeared(String packageName, int reason) {
1530            // remove all receivers associated with this package name
1531            synchronized (mLock) {
1532                ArrayList<Receiver> deadReceivers = null;
1533
1534                for (Receiver receiver : mReceivers.values()) {
1535                    if (receiver.mPackageName.equals(packageName)) {
1536                        if (deadReceivers == null) {
1537                            deadReceivers = new ArrayList<Receiver>();
1538                        }
1539                        deadReceivers.add(receiver);
1540                    }
1541                }
1542
1543                // perform removal outside of mReceivers loop
1544                if (deadReceivers != null) {
1545                    for (Receiver receiver : deadReceivers) {
1546                        removeUpdatesLocked(receiver);
1547                    }
1548                }
1549            }
1550        }
1551    };
1552
1553    // Wake locks
1554
1555    private void incrementPendingBroadcasts() {
1556        synchronized (mWakeLock) {
1557            if (mPendingBroadcasts++ == 0) {
1558                try {
1559                    mWakeLock.acquire();
1560                    log("Acquired wakelock");
1561                } catch (Exception e) {
1562                    // This is to catch a runtime exception thrown when we try to release an
1563                    // already released lock.
1564                    Slog.e(TAG, "exception in acquireWakeLock()", e);
1565                }
1566            }
1567        }
1568    }
1569
1570    private void decrementPendingBroadcasts() {
1571        synchronized (mWakeLock) {
1572            if (--mPendingBroadcasts == 0) {
1573                try {
1574                    // Release wake lock
1575                    if (mWakeLock.isHeld()) {
1576                        mWakeLock.release();
1577                        log("Released wakelock");
1578                    } else {
1579                        log("Can't release wakelock again!");
1580                    }
1581                } catch (Exception e) {
1582                    // This is to catch a runtime exception thrown when we try to release an
1583                    // already released lock.
1584                    Slog.e(TAG, "exception in releaseWakeLock()", e);
1585                }
1586            }
1587        }
1588    }
1589
1590    // Geocoder
1591
1592    @Override
1593    public boolean geocoderIsPresent() {
1594        return mGeocodeProvider != null;
1595    }
1596
1597    @Override
1598    public String getFromLocation(double latitude, double longitude, int maxResults,
1599            GeocoderParams params, List<Address> addrs) {
1600        if (mGeocodeProvider != null) {
1601            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1602                    params, addrs);
1603        }
1604        return null;
1605    }
1606
1607
1608    @Override
1609    public String getFromLocationName(String locationName,
1610            double lowerLeftLatitude, double lowerLeftLongitude,
1611            double upperRightLatitude, double upperRightLongitude, int maxResults,
1612            GeocoderParams params, List<Address> addrs) {
1613
1614        if (mGeocodeProvider != null) {
1615            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1616                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1617                    maxResults, params, addrs);
1618        }
1619        return null;
1620    }
1621
1622    // Mock Providers
1623
1624    private void checkMockPermissionsSafe() {
1625        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1626                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1627        if (!allowMocks) {
1628            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1629        }
1630
1631        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1632            PackageManager.PERMISSION_GRANTED) {
1633            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1634        }
1635    }
1636
1637    @Override
1638    public void addTestProvider(String name, ProviderProperties properties) {
1639        checkMockPermissionsSafe();
1640
1641        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1642            throw new IllegalArgumentException("Cannot mock the passive location provider");
1643        }
1644
1645        long identity = Binder.clearCallingIdentity();
1646        synchronized (mLock) {
1647            MockProvider provider = new MockProvider(name, this, properties);
1648            // remove the real provider if we are replacing GPS or network provider
1649            if (LocationManager.GPS_PROVIDER.equals(name)
1650                    || LocationManager.NETWORK_PROVIDER.equals(name)
1651                    || LocationManager.FUSED_PROVIDER.equals(name)) {
1652                LocationProviderInterface p = mProvidersByName.get(name);
1653                if (p != null) {
1654                    removeProviderLocked(p);
1655                }
1656            }
1657            if (mProvidersByName.get(name) != null) {
1658                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1659            }
1660            addProviderLocked(provider);
1661            mMockProviders.put(name, provider);
1662            mLastLocation.put(name, null);
1663            updateProvidersLocked();
1664        }
1665        Binder.restoreCallingIdentity(identity);
1666    }
1667
1668    @Override
1669    public void removeTestProvider(String provider) {
1670        checkMockPermissionsSafe();
1671        synchronized (mLock) {
1672            MockProvider mockProvider = mMockProviders.get(provider);
1673            if (mockProvider == null) {
1674                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1675            }
1676            long identity = Binder.clearCallingIdentity();
1677            removeProviderLocked(mProvidersByName.get(provider));
1678            mMockProviders.remove(mockProvider);
1679
1680            // reinstate real provider if available
1681            LocationProviderInterface realProvider = mRealProviders.get(provider);
1682            if (realProvider != null) {
1683                addProviderLocked(realProvider);
1684            }
1685            mLastLocation.put(provider, null);
1686            updateProvidersLocked();
1687            Binder.restoreCallingIdentity(identity);
1688        }
1689    }
1690
1691    @Override
1692    public void setTestProviderLocation(String provider, Location loc) {
1693        checkMockPermissionsSafe();
1694        synchronized (mLock) {
1695            MockProvider mockProvider = mMockProviders.get(provider);
1696            if (mockProvider == null) {
1697                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1698            }
1699            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1700            long identity = Binder.clearCallingIdentity();
1701            mockProvider.setLocation(loc);
1702            Binder.restoreCallingIdentity(identity);
1703        }
1704    }
1705
1706    @Override
1707    public void clearTestProviderLocation(String provider) {
1708        checkMockPermissionsSafe();
1709        synchronized (mLock) {
1710            MockProvider mockProvider = mMockProviders.get(provider);
1711            if (mockProvider == null) {
1712                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1713            }
1714            mockProvider.clearLocation();
1715        }
1716    }
1717
1718    @Override
1719    public void setTestProviderEnabled(String provider, boolean enabled) {
1720        checkMockPermissionsSafe();
1721        synchronized (mLock) {
1722            MockProvider mockProvider = mMockProviders.get(provider);
1723            if (mockProvider == null) {
1724                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1725            }
1726            long identity = Binder.clearCallingIdentity();
1727            if (enabled) {
1728                mockProvider.enable();
1729                mEnabledProviders.add(provider);
1730                mDisabledProviders.remove(provider);
1731            } else {
1732                mockProvider.disable();
1733                mEnabledProviders.remove(provider);
1734                mDisabledProviders.add(provider);
1735            }
1736            updateProvidersLocked();
1737            Binder.restoreCallingIdentity(identity);
1738        }
1739    }
1740
1741    @Override
1742    public void clearTestProviderEnabled(String provider) {
1743        checkMockPermissionsSafe();
1744        synchronized (mLock) {
1745            MockProvider mockProvider = mMockProviders.get(provider);
1746            if (mockProvider == null) {
1747                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1748            }
1749            long identity = Binder.clearCallingIdentity();
1750            mEnabledProviders.remove(provider);
1751            mDisabledProviders.remove(provider);
1752            updateProvidersLocked();
1753            Binder.restoreCallingIdentity(identity);
1754        }
1755    }
1756
1757    @Override
1758    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1759        checkMockPermissionsSafe();
1760        synchronized (mLock) {
1761            MockProvider mockProvider = mMockProviders.get(provider);
1762            if (mockProvider == null) {
1763                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1764            }
1765            mockProvider.setStatus(status, extras, updateTime);
1766        }
1767    }
1768
1769    @Override
1770    public void clearTestProviderStatus(String provider) {
1771        checkMockPermissionsSafe();
1772        synchronized (mLock) {
1773            MockProvider mockProvider = mMockProviders.get(provider);
1774            if (mockProvider == null) {
1775                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1776            }
1777            mockProvider.clearStatus();
1778        }
1779    }
1780
1781    private void log(String log) {
1782        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1783            Slog.d(TAG, log);
1784        }
1785    }
1786
1787    @Override
1788    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1789        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1790                != PackageManager.PERMISSION_GRANTED) {
1791            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
1792                    + Binder.getCallingPid()
1793                    + ", uid=" + Binder.getCallingUid());
1794            return;
1795        }
1796
1797        synchronized (mLock) {
1798            pw.println("Current Location Manager state:");
1799            pw.println("  Location Listeners:");
1800            for (Receiver receiver : mReceivers.values()) {
1801                pw.println("    " + receiver);
1802            }
1803            pw.println("  Records by Provider:");
1804            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1805                pw.println("    " + entry.getKey() + ":");
1806                for (UpdateRecord record : entry.getValue()) {
1807                    pw.println("      " + record);
1808                }
1809            }
1810            pw.println("  Last Known Locations:");
1811            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1812                String provider = entry.getKey();
1813                Location location = entry.getValue();
1814                pw.println("    " + provider + ": " + location);
1815            }
1816
1817            mGeofenceManager.dump(pw);
1818
1819            if (mEnabledProviders.size() > 0) {
1820                pw.println("  Enabled Providers:");
1821                for (String i : mEnabledProviders) {
1822                    pw.println("    " + i);
1823                }
1824
1825            }
1826            if (mDisabledProviders.size() > 0) {
1827                pw.println("  Disabled Providers:");
1828                for (String i : mDisabledProviders) {
1829                    pw.println("    " + i);
1830                }
1831            }
1832            pw.append("  ");
1833            mBlacklist.dump(pw);
1834            if (mMockProviders.size() > 0) {
1835                pw.println("  Mock Providers:");
1836                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
1837                    i.getValue().dump(pw, "      ");
1838                }
1839            }
1840
1841            pw.append("  fudger: ");
1842            mLocationFudger.dump(fd, pw,  args);
1843
1844            if (args.length > 0 && "short".equals(args[0])) {
1845                return;
1846            }
1847            for (LocationProviderInterface provider: mProviders) {
1848                pw.print(provider.getName() + " Internal State");
1849                if (provider instanceof LocationProviderProxy) {
1850                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
1851                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
1852                }
1853                pw.println(":");
1854                provider.dump(fd, pw, args);
1855            }
1856        }
1857    }
1858}
1859