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