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