LocationManagerService.java revision f429921e3a8b171771e268f23fc3fa909d791441
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.
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        String perms = checkPermission();
1297        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1298        if (ACCESS_COARSE_LOCATION.equals(perms) &&
1299                !isProviderAllowedByCoarsePermission(provider)) {
1300            throw new SecurityException("The \"" + provider +
1301                    "\" provider requires ACCESS_FINE_LOCATION permission");
1302        }
1303
1304        synchronized (mLock) {
1305            LocationProviderInterface p = mProvidersByName.get(provider);
1306            if (p == null) return false;
1307
1308            return isAllowedBySettingsLocked(provider);
1309        }
1310    }
1311
1312    private void checkCallerIsProvider() {
1313        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1314                == PackageManager.PERMISSION_GRANTED) {
1315            return;
1316        }
1317
1318        // Previously we only used the INSTALL_LOCATION_PROVIDER
1319        // check. But that is system or signature
1320        // protection level which is not flexible enough for
1321        // providers installed oustide the system image. So
1322        // also allow providers with a UID matching the
1323        // currently bound package name
1324
1325        int uid = Binder.getCallingUid();
1326
1327        if (mGeocodeProvider != null) {
1328            if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1329        }
1330        for (LocationProviderProxy proxy : mProxyProviders) {
1331            if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1332        }
1333        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1334                "or UID of a currently bound location provider");
1335    }
1336
1337    private boolean doesPackageHaveUid(int uid, String packageName) {
1338        if (packageName == null) {
1339            return false;
1340        }
1341        try {
1342            ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1343            if (appInfo.uid != uid) {
1344                return false;
1345            }
1346        } catch (NameNotFoundException e) {
1347            return false;
1348        }
1349        return true;
1350    }
1351
1352    @Override
1353    public void reportLocation(Location location, boolean passive) {
1354        checkCallerIsProvider();
1355
1356        if (!location.isComplete()) {
1357            Log.w(TAG, "Dropping incomplete location: " + location);
1358            return;
1359        }
1360
1361        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1362        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
1363        m.arg1 = (passive ? 1 : 0);
1364        mLocationHandler.sendMessageAtFrontOfQueue(m);
1365    }
1366
1367
1368    private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1369        // Always broadcast the first update
1370        if (lastLoc == null) {
1371            return true;
1372        }
1373
1374        // Check whether sufficient time has passed
1375        long minTime = record.mRequest.getFastestInterval();
1376        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
1377        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
1378            return false;
1379        }
1380
1381        // Check whether sufficient distance has been traveled
1382        double minDistance = record.mRequest.getSmallestDisplacement();
1383        if (minDistance > 0.0) {
1384            if (loc.distanceTo(lastLoc) <= minDistance) {
1385                return false;
1386            }
1387        }
1388
1389        return true;
1390    }
1391
1392    private void handleLocationChangedLocked(Location location, boolean passive) {
1393        if (D) Log.d(TAG, "incoming location: " + location);
1394
1395        long now = SystemClock.elapsedRealtime();
1396        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
1397        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1398        if (records == null || records.size() == 0) return;
1399
1400        LocationProviderInterface p = mProvidersByName.get(provider);
1401        if (p == null) return;
1402
1403        // Update last known locations
1404        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1405        Location lastNoGPSLocation = null;
1406        Location lastLocation = mLastLocation.get(provider);
1407        if (lastLocation == null) {
1408            lastLocation = new Location(provider);
1409            mLastLocation.put(provider, lastLocation);
1410        } else {
1411            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1412            if (noGPSLocation == null && lastNoGPSLocation != null) {
1413                // New location has no no-GPS location: adopt last no-GPS location. This is set
1414                // directly into location because we do not want to notify COARSE clients.
1415                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1416            }
1417        }
1418        lastLocation.set(location);
1419
1420        // Fetch coarse location
1421        Location coarseLocation = null;
1422        if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1423            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1424        }
1425
1426        // Fetch latest status update time
1427        long newStatusUpdateTime = p.getStatusUpdateTime();
1428
1429       // Get latest status
1430        Bundle extras = new Bundle();
1431        int status = p.getStatus(extras);
1432
1433        ArrayList<Receiver> deadReceivers = null;
1434        ArrayList<UpdateRecord> deadUpdateRecords = null;
1435
1436        // Broadcast location or status to all listeners
1437        for (UpdateRecord r : records) {
1438            Receiver receiver = r.mReceiver;
1439            boolean receiverDead = false;
1440
1441            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1442                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1443                        receiver.mPackageName);
1444                continue;
1445            }
1446
1447            Location notifyLocation = null;
1448            if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1449                notifyLocation = lastLocation;  // use fine location
1450            } else {
1451                notifyLocation = coarseLocation;  // use coarse location if available
1452            }
1453            if (notifyLocation != null) {
1454                Location lastLoc = r.mLastFixBroadcast;
1455                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1456                    if (lastLoc == null) {
1457                        lastLoc = new Location(notifyLocation);
1458                        r.mLastFixBroadcast = lastLoc;
1459                    } else {
1460                        lastLoc.set(notifyLocation);
1461                    }
1462                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
1463                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1464                        receiverDead = true;
1465                    }
1466                }
1467            }
1468
1469            long prevStatusUpdateTime = r.mLastStatusBroadcast;
1470            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1471                    (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1472
1473                r.mLastStatusBroadcast = newStatusUpdateTime;
1474                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1475                    receiverDead = true;
1476                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1477                }
1478            }
1479
1480            // track expired records
1481            if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1482                if (deadUpdateRecords == null) {
1483                    deadUpdateRecords = new ArrayList<UpdateRecord>();
1484                }
1485                deadUpdateRecords.add(r);
1486            }
1487            // track dead receivers
1488            if (receiverDead) {
1489                if (deadReceivers == null) {
1490                    deadReceivers = new ArrayList<Receiver>();
1491                }
1492                if (!deadReceivers.contains(receiver)) {
1493                    deadReceivers.add(receiver);
1494                }
1495            }
1496        }
1497
1498        // remove dead records and receivers outside the loop
1499        if (deadReceivers != null) {
1500            for (Receiver receiver : deadReceivers) {
1501                removeUpdatesLocked(receiver);
1502            }
1503        }
1504        if (deadUpdateRecords != null) {
1505            for (UpdateRecord r : deadUpdateRecords) {
1506                r.disposeLocked(true);
1507            }
1508        }
1509    }
1510
1511    private class LocationWorkerHandler extends Handler {
1512        @Override
1513        public void handleMessage(Message msg) {
1514            switch (msg.what) {
1515                case MSG_LOCATION_CHANGED:
1516                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1517                    break;
1518            }
1519        }
1520    }
1521
1522    private void handleLocationChanged(Location location, boolean passive) {
1523        String provider = location.getProvider();
1524
1525        if (!passive) {
1526            // notify passive provider of the new location
1527            mPassiveProvider.updateLocation(location);
1528        }
1529
1530        synchronized (mLock) {
1531            if (isAllowedBySettingsLocked(provider)) {
1532                handleLocationChangedLocked(location, passive);
1533            }
1534        }
1535    }
1536
1537    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1538        @Override
1539        public void onPackageDisappeared(String packageName, int reason) {
1540            // remove all receivers associated with this package name
1541            synchronized (mLock) {
1542                ArrayList<Receiver> deadReceivers = null;
1543
1544                for (Receiver receiver : mReceivers.values()) {
1545                    if (receiver.mPackageName.equals(packageName)) {
1546                        if (deadReceivers == null) {
1547                            deadReceivers = new ArrayList<Receiver>();
1548                        }
1549                        deadReceivers.add(receiver);
1550                    }
1551                }
1552
1553                // perform removal outside of mReceivers loop
1554                if (deadReceivers != null) {
1555                    for (Receiver receiver : deadReceivers) {
1556                        removeUpdatesLocked(receiver);
1557                    }
1558                }
1559            }
1560        }
1561    };
1562
1563    // Wake locks
1564
1565    private void incrementPendingBroadcasts() {
1566        synchronized (mWakeLock) {
1567            if (mPendingBroadcasts++ == 0) {
1568                try {
1569                    mWakeLock.acquire();
1570                    log("Acquired wakelock");
1571                } catch (Exception e) {
1572                    // This is to catch a runtime exception thrown when we try to release an
1573                    // already released lock.
1574                    Slog.e(TAG, "exception in acquireWakeLock()", e);
1575                }
1576            }
1577        }
1578    }
1579
1580    private void decrementPendingBroadcasts() {
1581        synchronized (mWakeLock) {
1582            if (--mPendingBroadcasts == 0) {
1583                try {
1584                    // Release wake lock
1585                    if (mWakeLock.isHeld()) {
1586                        mWakeLock.release();
1587                        log("Released wakelock");
1588                    } else {
1589                        log("Can't release wakelock again!");
1590                    }
1591                } catch (Exception e) {
1592                    // This is to catch a runtime exception thrown when we try to release an
1593                    // already released lock.
1594                    Slog.e(TAG, "exception in releaseWakeLock()", e);
1595                }
1596            }
1597        }
1598    }
1599
1600    // Geocoder
1601
1602    @Override
1603    public boolean geocoderIsPresent() {
1604        return mGeocodeProvider != null;
1605    }
1606
1607    @Override
1608    public String getFromLocation(double latitude, double longitude, int maxResults,
1609            GeocoderParams params, List<Address> addrs) {
1610        if (mGeocodeProvider != null) {
1611            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1612                    params, addrs);
1613        }
1614        return null;
1615    }
1616
1617
1618    @Override
1619    public String getFromLocationName(String locationName,
1620            double lowerLeftLatitude, double lowerLeftLongitude,
1621            double upperRightLatitude, double upperRightLongitude, int maxResults,
1622            GeocoderParams params, List<Address> addrs) {
1623
1624        if (mGeocodeProvider != null) {
1625            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1626                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1627                    maxResults, params, addrs);
1628        }
1629        return null;
1630    }
1631
1632    // Mock Providers
1633
1634    private void checkMockPermissionsSafe() {
1635        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1636                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1637        if (!allowMocks) {
1638            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1639        }
1640
1641        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1642            PackageManager.PERMISSION_GRANTED) {
1643            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1644        }
1645    }
1646
1647    @Override
1648    public void addTestProvider(String name, ProviderProperties properties) {
1649        checkMockPermissionsSafe();
1650
1651        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1652            throw new IllegalArgumentException("Cannot mock the passive location provider");
1653        }
1654
1655        long identity = Binder.clearCallingIdentity();
1656        synchronized (mLock) {
1657            MockProvider provider = new MockProvider(name, this, properties);
1658            // remove the real provider if we are replacing GPS or network provider
1659            if (LocationManager.GPS_PROVIDER.equals(name)
1660                    || LocationManager.NETWORK_PROVIDER.equals(name)
1661                    || LocationManager.FUSED_PROVIDER.equals(name)) {
1662                LocationProviderInterface p = mProvidersByName.get(name);
1663                if (p != null) {
1664                    removeProviderLocked(p);
1665                }
1666            }
1667            if (mProvidersByName.get(name) != null) {
1668                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1669            }
1670            addProviderLocked(provider);
1671            mMockProviders.put(name, provider);
1672            mLastLocation.put(name, null);
1673            updateProvidersLocked();
1674        }
1675        Binder.restoreCallingIdentity(identity);
1676    }
1677
1678    @Override
1679    public void removeTestProvider(String provider) {
1680        checkMockPermissionsSafe();
1681        synchronized (mLock) {
1682            MockProvider mockProvider = mMockProviders.get(provider);
1683            if (mockProvider == null) {
1684                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1685            }
1686            long identity = Binder.clearCallingIdentity();
1687            removeProviderLocked(mProvidersByName.get(provider));
1688            mMockProviders.remove(mockProvider);
1689
1690            // reinstate real provider if available
1691            LocationProviderInterface realProvider = mRealProviders.get(provider);
1692            if (realProvider != null) {
1693                addProviderLocked(realProvider);
1694            }
1695            mLastLocation.put(provider, null);
1696            updateProvidersLocked();
1697            Binder.restoreCallingIdentity(identity);
1698        }
1699    }
1700
1701    @Override
1702    public void setTestProviderLocation(String provider, Location loc) {
1703        checkMockPermissionsSafe();
1704        synchronized (mLock) {
1705            MockProvider mockProvider = mMockProviders.get(provider);
1706            if (mockProvider == null) {
1707                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1708            }
1709            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1710            long identity = Binder.clearCallingIdentity();
1711            mockProvider.setLocation(loc);
1712            Binder.restoreCallingIdentity(identity);
1713        }
1714    }
1715
1716    @Override
1717    public void clearTestProviderLocation(String provider) {
1718        checkMockPermissionsSafe();
1719        synchronized (mLock) {
1720            MockProvider mockProvider = mMockProviders.get(provider);
1721            if (mockProvider == null) {
1722                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1723            }
1724            mockProvider.clearLocation();
1725        }
1726    }
1727
1728    @Override
1729    public void setTestProviderEnabled(String provider, boolean enabled) {
1730        checkMockPermissionsSafe();
1731        synchronized (mLock) {
1732            MockProvider mockProvider = mMockProviders.get(provider);
1733            if (mockProvider == null) {
1734                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1735            }
1736            long identity = Binder.clearCallingIdentity();
1737            if (enabled) {
1738                mockProvider.enable();
1739                mEnabledProviders.add(provider);
1740                mDisabledProviders.remove(provider);
1741            } else {
1742                mockProvider.disable();
1743                mEnabledProviders.remove(provider);
1744                mDisabledProviders.add(provider);
1745            }
1746            updateProvidersLocked();
1747            Binder.restoreCallingIdentity(identity);
1748        }
1749    }
1750
1751    @Override
1752    public void clearTestProviderEnabled(String provider) {
1753        checkMockPermissionsSafe();
1754        synchronized (mLock) {
1755            MockProvider mockProvider = mMockProviders.get(provider);
1756            if (mockProvider == null) {
1757                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1758            }
1759            long identity = Binder.clearCallingIdentity();
1760            mEnabledProviders.remove(provider);
1761            mDisabledProviders.remove(provider);
1762            updateProvidersLocked();
1763            Binder.restoreCallingIdentity(identity);
1764        }
1765    }
1766
1767    @Override
1768    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1769        checkMockPermissionsSafe();
1770        synchronized (mLock) {
1771            MockProvider mockProvider = mMockProviders.get(provider);
1772            if (mockProvider == null) {
1773                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1774            }
1775            mockProvider.setStatus(status, extras, updateTime);
1776        }
1777    }
1778
1779    @Override
1780    public void clearTestProviderStatus(String provider) {
1781        checkMockPermissionsSafe();
1782        synchronized (mLock) {
1783            MockProvider mockProvider = mMockProviders.get(provider);
1784            if (mockProvider == null) {
1785                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1786            }
1787            mockProvider.clearStatus();
1788        }
1789    }
1790
1791    private void log(String log) {
1792        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1793            Slog.d(TAG, log);
1794        }
1795    }
1796
1797    @Override
1798    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1799        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1800                != PackageManager.PERMISSION_GRANTED) {
1801            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
1802                    + Binder.getCallingPid()
1803                    + ", uid=" + Binder.getCallingUid());
1804            return;
1805        }
1806
1807        synchronized (mLock) {
1808            pw.println("Current Location Manager state:");
1809            pw.println("  Location Listeners:");
1810            for (Receiver receiver : mReceivers.values()) {
1811                pw.println("    " + receiver);
1812            }
1813            pw.println("  Records by Provider:");
1814            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1815                pw.println("    " + entry.getKey() + ":");
1816                for (UpdateRecord record : entry.getValue()) {
1817                    pw.println("      " + record);
1818                }
1819            }
1820            pw.println("  Last Known Locations:");
1821            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1822                String provider = entry.getKey();
1823                Location location = entry.getValue();
1824                pw.println("    " + provider + ": " + location);
1825            }
1826
1827            mGeofenceManager.dump(pw);
1828
1829            if (mEnabledProviders.size() > 0) {
1830                pw.println("  Enabled Providers:");
1831                for (String i : mEnabledProviders) {
1832                    pw.println("    " + i);
1833                }
1834
1835            }
1836            if (mDisabledProviders.size() > 0) {
1837                pw.println("  Disabled Providers:");
1838                for (String i : mDisabledProviders) {
1839                    pw.println("    " + i);
1840                }
1841            }
1842            pw.append("  ");
1843            mBlacklist.dump(pw);
1844            if (mMockProviders.size() > 0) {
1845                pw.println("  Mock Providers:");
1846                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
1847                    i.getValue().dump(pw, "      ");
1848                }
1849            }
1850
1851            pw.append("  fudger: ");
1852            mLocationFudger.dump(fd, pw,  args);
1853
1854            if (args.length > 0 && "short".equals(args[0])) {
1855                return;
1856            }
1857            for (LocationProviderInterface provider: mProviders) {
1858                pw.print(provider.getName() + " Internal State");
1859                if (provider instanceof LocationProviderProxy) {
1860                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
1861                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
1862                }
1863                pw.println(":");
1864                provider.dump(fd, pw, args);
1865            }
1866        }
1867    }
1868}
1869