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