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