LocationManagerService.java revision 8dbb63419bef8678cf92ebae1d43f549f50987c7
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 String checkPermissionAndRequest(LocationRequest request) {
920        String perm = checkPermission();
921
922        if (ACCESS_COARSE_LOCATION.equals(perm)) {
923             switch (request.getQuality()) {
924                 case LocationRequest.ACCURACY_FINE:
925                     request.setQuality(LocationRequest.ACCURACY_BLOCK);
926                     break;
927                 case LocationRequest.POWER_HIGH:
928                     request.setQuality(LocationRequest.POWER_LOW);
929                     break;
930             }
931             // throttle
932             if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
933                 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
934             }
935             if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
936                 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
937             }
938        }
939        // make getFastestInterval() the minimum of interval and fastest interval
940        if (request.getFastestInterval() > request.getInterval()) {
941            request.setFastestInterval(request.getInterval());
942        }
943        return perm;
944    }
945
946    private void checkPackageName(String packageName) {
947        if (packageName == null) {
948            throw new SecurityException("invalid package name: " + packageName);
949        }
950        int uid = Binder.getCallingUid();
951        String[] packages = mPackageManager.getPackagesForUid(uid);
952        if (packages == null) {
953            throw new SecurityException("invalid UID " + uid);
954        }
955        for (String pkg : packages) {
956            if (packageName.equals(pkg)) return;
957        }
958        throw new SecurityException("invalid package name: " + packageName);
959    }
960
961    private void checkPendingIntent(PendingIntent intent) {
962        if (intent == null) {
963            throw new IllegalArgumentException("invalid pending intent: " + intent);
964        }
965    }
966
967    private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
968            int pid, int uid, String packageName) {
969        if (intent == null && listener == null) {
970            throw new IllegalArgumentException("need eiter listener or intent");
971        } else if (intent != null && listener != null) {
972            throw new IllegalArgumentException("cannot register both listener and intent");
973        } else if (intent != null) {
974            checkPendingIntent(intent);
975            return getReceiver(intent, pid, uid, packageName);
976        } else {
977            return getReceiver(listener, pid, uid, packageName);
978        }
979    }
980
981    @Override
982    public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
983            PendingIntent intent, String packageName) {
984        if (request == null) request = DEFAULT_LOCATION_REQUEST;
985        checkPackageName(packageName);
986        checkPermissionAndRequest(request);
987
988        final int pid = Binder.getCallingPid();
989        final int uid = Binder.getCallingUid();
990        Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
991
992        // providers may use public location API's, need to clear identity
993        long identity = Binder.clearCallingIdentity();
994        try {
995            synchronized (mLock) {
996                requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
997            }
998        } finally {
999            Binder.restoreCallingIdentity(identity);
1000        }
1001    }
1002
1003    private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1004            int pid, int uid, String packageName) {
1005        // Figure out the provider. Either its explicitly request (legacy use cases), or
1006        // use the fused provider
1007        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1008        String name = request.getProvider();
1009        if (name == null) name = LocationManager.FUSED_PROVIDER;
1010        LocationProviderInterface provider = mProvidersByName.get(name);
1011        if (provider == null) {
1012            throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1013        }
1014
1015        Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1016                name + " " + request + " from " + packageName + "(" + uid + ")");
1017
1018        UpdateRecord record = new UpdateRecord(name, request, receiver);
1019        UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1020        if (oldRecord != null) {
1021            oldRecord.disposeLocked(false);
1022        }
1023
1024        boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1025        if (isProviderEnabled) {
1026            applyRequirementsLocked(name);
1027        } else {
1028            // Notify the listener that updates are currently disabled
1029            receiver.callProviderEnabledLocked(name, false);
1030        }
1031    }
1032
1033    @Override
1034    public void removeUpdates(ILocationListener listener, PendingIntent intent,
1035            String packageName) {
1036        checkPackageName(packageName);
1037        checkPermission();
1038        final int pid = Binder.getCallingPid();
1039        final int uid = Binder.getCallingUid();
1040        Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1041
1042        // providers may use public location API's, need to clear identity
1043        long identity = Binder.clearCallingIdentity();
1044        try {
1045            synchronized (mLock) {
1046                removeUpdatesLocked(receiver);
1047            }
1048        } finally {
1049            Binder.restoreCallingIdentity(identity);
1050        }
1051    }
1052
1053    private void removeUpdatesLocked(Receiver receiver) {
1054        Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1055
1056        if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1057            receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1058            synchronized (receiver) {
1059                if (receiver.mPendingBroadcasts > 0) {
1060                    decrementPendingBroadcasts();
1061                    receiver.mPendingBroadcasts = 0;
1062                }
1063            }
1064        }
1065
1066        // Record which providers were associated with this listener
1067        HashSet<String> providers = new HashSet<String>();
1068        HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1069        if (oldRecords != null) {
1070            // Call dispose() on the obsolete update records.
1071            for (UpdateRecord record : oldRecords.values()) {
1072                record.disposeLocked(false);
1073            }
1074            // Accumulate providers
1075            providers.addAll(oldRecords.keySet());
1076        }
1077
1078        // update provider
1079        for (String provider : providers) {
1080            // If provider is already disabled, don't need to do anything
1081            if (!isAllowedBySettingsLocked(provider)) {
1082                continue;
1083            }
1084
1085            applyRequirementsLocked(provider);
1086        }
1087    }
1088
1089    @Override
1090    public Location getLastLocation(LocationRequest request, String packageName) {
1091        if (D) Log.d(TAG, "getLastLocation: " + request);
1092        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1093        String perm = checkPermissionAndRequest(request);
1094        checkPackageName(packageName);
1095
1096        if (mBlacklist.isBlacklisted(packageName)) {
1097            if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1098                    packageName);
1099            return null;
1100        }
1101
1102        synchronized (mLock) {
1103            // Figure out the provider. Either its explicitly request (deprecated API's),
1104            // or use the fused provider
1105            String name = request.getProvider();
1106            if (name == null) name = LocationManager.FUSED_PROVIDER;
1107            LocationProviderInterface provider = mProvidersByName.get(name);
1108            if (provider == null) return null;
1109
1110            if (!isAllowedBySettingsLocked(name)) return null;
1111
1112            Location location = mLastLocation.get(name);
1113            if (ACCESS_FINE_LOCATION.equals(perm)) {
1114                return location;
1115            } else {
1116                return mLocationFudger.getOrCreate(location);
1117            }
1118        }
1119    }
1120
1121    @Override
1122    public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1123            String packageName) {
1124        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1125        checkGeofencePermission();
1126        checkPermissionAndRequest(request);
1127        checkPendingIntent(intent);
1128        checkPackageName(packageName);
1129
1130        if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1131
1132        // geo-fence manager uses the public location API, need to clear identity
1133        int uid = Binder.getCallingUid();
1134        long identity = Binder.clearCallingIdentity();
1135        try {
1136            mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1137        } finally {
1138            Binder.restoreCallingIdentity(identity);
1139        }
1140    }
1141
1142    @Override
1143    public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1144        checkGeofencePermission();
1145        checkPendingIntent(intent);
1146        checkPackageName(packageName);
1147
1148        if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1149
1150        // geo-fence manager uses the public location API, need to clear identity
1151        long identity = Binder.clearCallingIdentity();
1152        try {
1153            mGeofenceManager.removeFence(geofence, intent);
1154        } finally {
1155            Binder.restoreCallingIdentity(identity);
1156        }
1157    }
1158
1159
1160    @Override
1161    public boolean addGpsStatusListener(IGpsStatusListener listener) {
1162        if (mGpsStatusProvider == null) {
1163            return false;
1164        }
1165        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
1166                PackageManager.PERMISSION_GRANTED) {
1167            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1168        }
1169
1170        try {
1171            mGpsStatusProvider.addGpsStatusListener(listener);
1172        } catch (RemoteException e) {
1173            Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
1174            return false;
1175        }
1176        return true;
1177    }
1178
1179    @Override
1180    public void removeGpsStatusListener(IGpsStatusListener listener) {
1181        synchronized (mLock) {
1182            try {
1183                mGpsStatusProvider.removeGpsStatusListener(listener);
1184            } catch (Exception e) {
1185                Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1186            }
1187        }
1188    }
1189
1190    @Override
1191    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1192        if (provider == null) {
1193            // throw NullPointerException to remain compatible with previous implementation
1194            throw new NullPointerException();
1195        }
1196
1197        checkPermission();
1198        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1199        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1200                != PackageManager.PERMISSION_GRANTED)) {
1201            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1202        }
1203
1204        synchronized (mLock) {
1205            LocationProviderInterface p = mProvidersByName.get(provider);
1206            if (p == null) return false;
1207
1208            return p.sendExtraCommand(command, extras);
1209        }
1210    }
1211
1212    @Override
1213    public boolean sendNiResponse(int notifId, int userResponse) {
1214        if (Binder.getCallingUid() != Process.myUid()) {
1215            throw new SecurityException(
1216                    "calling sendNiResponse from outside of the system is not allowed");
1217        }
1218        try {
1219            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1220        } catch (RemoteException e) {
1221            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1222            return false;
1223        }
1224    }
1225
1226    /**
1227     * @return null if the provider does not exist
1228     * @throws SecurityException if the provider is not allowed to be
1229     * accessed by the caller
1230     */
1231    @Override
1232    public ProviderProperties getProviderProperties(String provider) {
1233        checkPermission();
1234
1235        LocationProviderInterface p;
1236        synchronized (mLock) {
1237            p = mProvidersByName.get(provider);
1238        }
1239
1240        if (p == null) return null;
1241        return p.getProperties();
1242    }
1243
1244    @Override
1245    public boolean isProviderEnabled(String provider) {
1246        checkPermission();
1247        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1248
1249        synchronized (mLock) {
1250            LocationProviderInterface p = mProvidersByName.get(provider);
1251            if (p == null) return false;
1252
1253            return isAllowedBySettingsLocked(provider);
1254        }
1255    }
1256
1257    private void checkCallerIsProvider() {
1258        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1259                == PackageManager.PERMISSION_GRANTED) {
1260            return;
1261        }
1262
1263        // Previously we only used the INSTALL_LOCATION_PROVIDER
1264        // check. But that is system or signature
1265        // protection level which is not flexible enough for
1266        // providers installed oustide the system image. So
1267        // also allow providers with a UID matching the
1268        // currently bound package name
1269
1270        int uid = Binder.getCallingUid();
1271
1272        if (mGeocodeProvider != null) {
1273            if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1274        }
1275        for (LocationProviderProxy proxy : mProxyProviders) {
1276            if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1277        }
1278        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1279                "or UID of a currently bound location provider");
1280    }
1281
1282    private boolean doesPackageHaveUid(int uid, String packageName) {
1283        if (packageName == null) {
1284            return false;
1285        }
1286        try {
1287            ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1288            if (appInfo.uid != uid) {
1289                return false;
1290            }
1291        } catch (NameNotFoundException e) {
1292            return false;
1293        }
1294        return true;
1295    }
1296
1297    @Override
1298    public void reportLocation(Location location, boolean passive) {
1299        checkCallerIsProvider();
1300
1301        if (!location.isComplete()) {
1302            Log.w(TAG, "Dropping incomplete location: " + location);
1303            return;
1304        }
1305
1306        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1307        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
1308        m.arg1 = (passive ? 1 : 0);
1309        mLocationHandler.sendMessageAtFrontOfQueue(m);
1310    }
1311
1312
1313    private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1314        // Always broadcast the first update
1315        if (lastLoc == null) {
1316            return true;
1317        }
1318
1319        // Check whether sufficient time has passed
1320        long minTime = record.mRequest.getFastestInterval();
1321        long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
1322        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
1323            return false;
1324        }
1325
1326        // Check whether sufficient distance has been traveled
1327        double minDistance = record.mRequest.getSmallestDisplacement();
1328        if (minDistance > 0.0) {
1329            if (loc.distanceTo(lastLoc) <= minDistance) {
1330                return false;
1331            }
1332        }
1333
1334        return true;
1335    }
1336
1337    private void handleLocationChangedLocked(Location location, boolean passive) {
1338        if (D) Log.d(TAG, "incoming location: " + location);
1339
1340        long now = SystemClock.elapsedRealtime();
1341        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
1342        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1343        if (records == null || records.size() == 0) return;
1344
1345        LocationProviderInterface p = mProvidersByName.get(provider);
1346        if (p == null) return;
1347
1348        // Add the coarse location as an extra
1349        Location coarse = mLocationFudger.getOrCreate(location);
1350
1351        // Update last known locations
1352        Location lastLocation = mLastLocation.get(provider);
1353        if (lastLocation == null) {
1354            lastLocation = new Location(provider);
1355            mLastLocation.put(provider, lastLocation);
1356        }
1357        lastLocation.set(location);
1358
1359        // Fetch latest status update time
1360        long newStatusUpdateTime = p.getStatusUpdateTime();
1361
1362       // Get latest status
1363        Bundle extras = new Bundle();
1364        int status = p.getStatus(extras);
1365
1366        ArrayList<Receiver> deadReceivers = null;
1367        ArrayList<UpdateRecord> deadUpdateRecords = null;
1368
1369        // Broadcast location or status to all listeners
1370        for (UpdateRecord r : records) {
1371            Receiver receiver = r.mReceiver;
1372            boolean receiverDead = false;
1373
1374            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1375                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1376                        receiver.mPackageName);
1377                continue;
1378            }
1379
1380            if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1381                location = lastLocation;  // use fine location
1382            } else {
1383                location = coarse;  // use coarse location
1384            }
1385
1386            Location lastLoc = r.mLastFixBroadcast;
1387            if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1388                if (lastLoc == null) {
1389                    lastLoc = new Location(location);
1390                    r.mLastFixBroadcast = lastLoc;
1391                } else {
1392                    lastLoc.set(location);
1393                }
1394                if (!receiver.callLocationChangedLocked(location)) {
1395                    Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1396                    receiverDead = true;
1397                }
1398            }
1399
1400            long prevStatusUpdateTime = r.mLastStatusBroadcast;
1401            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1402                (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1403
1404                r.mLastStatusBroadcast = newStatusUpdateTime;
1405                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1406                    receiverDead = true;
1407                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1408                }
1409            }
1410
1411            // track expired records
1412            if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1413                if (deadUpdateRecords == null) {
1414                    deadUpdateRecords = new ArrayList<UpdateRecord>();
1415                }
1416                deadUpdateRecords.add(r);
1417            }
1418            // track dead receivers
1419            if (receiverDead) {
1420                if (deadReceivers == null) {
1421                    deadReceivers = new ArrayList<Receiver>();
1422                }
1423                if (!deadReceivers.contains(receiver)) {
1424                    deadReceivers.add(receiver);
1425                }
1426            }
1427        }
1428
1429        // remove dead records and receivers outside the loop
1430        if (deadReceivers != null) {
1431            for (Receiver receiver : deadReceivers) {
1432                removeUpdatesLocked(receiver);
1433            }
1434        }
1435        if (deadUpdateRecords != null) {
1436            for (UpdateRecord r : deadUpdateRecords) {
1437                r.disposeLocked(true);
1438            }
1439        }
1440    }
1441
1442    private class LocationWorkerHandler extends Handler {
1443        @Override
1444        public void handleMessage(Message msg) {
1445            switch (msg.what) {
1446                case MSG_LOCATION_CHANGED:
1447                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1448                    break;
1449            }
1450        }
1451    }
1452
1453    private void handleLocationChanged(Location location, boolean passive) {
1454        String provider = location.getProvider();
1455
1456        if (!passive) {
1457            // notify passive provider of the new location
1458            mPassiveProvider.updateLocation(location);
1459        }
1460
1461        synchronized (mLock) {
1462            if (isAllowedBySettingsLocked(provider)) {
1463                handleLocationChangedLocked(location, passive);
1464            }
1465        }
1466    }
1467
1468    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1469        @Override
1470        public void onPackageDisappeared(String packageName, int reason) {
1471            // remove all receivers associated with this package name
1472            synchronized (mLock) {
1473                ArrayList<Receiver> deadReceivers = null;
1474
1475                for (Receiver receiver : mReceivers.values()) {
1476                    if (receiver.mPackageName.equals(packageName)) {
1477                        if (deadReceivers == null) {
1478                            deadReceivers = new ArrayList<Receiver>();
1479                        }
1480                        deadReceivers.add(receiver);
1481                    }
1482                }
1483
1484                // perform removal outside of mReceivers loop
1485                if (deadReceivers != null) {
1486                    for (Receiver receiver : deadReceivers) {
1487                        removeUpdatesLocked(receiver);
1488                    }
1489                }
1490            }
1491        }
1492    };
1493
1494    // Wake locks
1495
1496    private void incrementPendingBroadcasts() {
1497        synchronized (mWakeLock) {
1498            if (mPendingBroadcasts++ == 0) {
1499                try {
1500                    mWakeLock.acquire();
1501                    log("Acquired wakelock");
1502                } catch (Exception e) {
1503                    // This is to catch a runtime exception thrown when we try to release an
1504                    // already released lock.
1505                    Slog.e(TAG, "exception in acquireWakeLock()", e);
1506                }
1507            }
1508        }
1509    }
1510
1511    private void decrementPendingBroadcasts() {
1512        synchronized (mWakeLock) {
1513            if (--mPendingBroadcasts == 0) {
1514                try {
1515                    // Release wake lock
1516                    if (mWakeLock.isHeld()) {
1517                        mWakeLock.release();
1518                        log("Released wakelock");
1519                    } else {
1520                        log("Can't release wakelock again!");
1521                    }
1522                } catch (Exception e) {
1523                    // This is to catch a runtime exception thrown when we try to release an
1524                    // already released lock.
1525                    Slog.e(TAG, "exception in releaseWakeLock()", e);
1526                }
1527            }
1528        }
1529    }
1530
1531    // Geocoder
1532
1533    @Override
1534    public boolean geocoderIsPresent() {
1535        return mGeocodeProvider != null;
1536    }
1537
1538    @Override
1539    public String getFromLocation(double latitude, double longitude, int maxResults,
1540            GeocoderParams params, List<Address> addrs) {
1541        if (mGeocodeProvider != null) {
1542            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1543                    params, addrs);
1544        }
1545        return null;
1546    }
1547
1548
1549    @Override
1550    public String getFromLocationName(String locationName,
1551            double lowerLeftLatitude, double lowerLeftLongitude,
1552            double upperRightLatitude, double upperRightLongitude, int maxResults,
1553            GeocoderParams params, List<Address> addrs) {
1554
1555        if (mGeocodeProvider != null) {
1556            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1557                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1558                    maxResults, params, addrs);
1559        }
1560        return null;
1561    }
1562
1563    // Mock Providers
1564
1565    private void checkMockPermissionsSafe() {
1566        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1567                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1568        if (!allowMocks) {
1569            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1570        }
1571
1572        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1573            PackageManager.PERMISSION_GRANTED) {
1574            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1575        }
1576    }
1577
1578    @Override
1579    public void addTestProvider(String name, ProviderProperties properties) {
1580        checkMockPermissionsSafe();
1581
1582        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1583            throw new IllegalArgumentException("Cannot mock the passive location provider");
1584        }
1585
1586        long identity = Binder.clearCallingIdentity();
1587        synchronized (mLock) {
1588            MockProvider provider = new MockProvider(name, this, properties);
1589            // remove the real provider if we are replacing GPS or network provider
1590            if (LocationManager.GPS_PROVIDER.equals(name)
1591                    || LocationManager.NETWORK_PROVIDER.equals(name)
1592                    || LocationManager.FUSED_PROVIDER.equals(name)) {
1593                LocationProviderInterface p = mProvidersByName.get(name);
1594                if (p != null) {
1595                    removeProviderLocked(p);
1596                }
1597            }
1598            if (mProvidersByName.get(name) != null) {
1599                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1600            }
1601            addProviderLocked(provider);
1602            mMockProviders.put(name, provider);
1603            mLastLocation.put(name, null);
1604            updateProvidersLocked();
1605        }
1606        Binder.restoreCallingIdentity(identity);
1607    }
1608
1609    @Override
1610    public void removeTestProvider(String provider) {
1611        checkMockPermissionsSafe();
1612        synchronized (mLock) {
1613            MockProvider mockProvider = mMockProviders.get(provider);
1614            if (mockProvider == null) {
1615                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1616            }
1617            long identity = Binder.clearCallingIdentity();
1618            removeProviderLocked(mProvidersByName.get(provider));
1619            mMockProviders.remove(mockProvider);
1620
1621            // reinstate real provider if available
1622            LocationProviderInterface realProvider = mRealProviders.get(provider);
1623            if (realProvider != null) {
1624                addProviderLocked(realProvider);
1625            }
1626            mLastLocation.put(provider, null);
1627            updateProvidersLocked();
1628            Binder.restoreCallingIdentity(identity);
1629        }
1630    }
1631
1632    @Override
1633    public void setTestProviderLocation(String provider, Location loc) {
1634        checkMockPermissionsSafe();
1635        synchronized (mLock) {
1636            MockProvider mockProvider = mMockProviders.get(provider);
1637            if (mockProvider == null) {
1638                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1639            }
1640            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1641            long identity = Binder.clearCallingIdentity();
1642            mockProvider.setLocation(loc);
1643            Binder.restoreCallingIdentity(identity);
1644        }
1645    }
1646
1647    @Override
1648    public void clearTestProviderLocation(String provider) {
1649        checkMockPermissionsSafe();
1650        synchronized (mLock) {
1651            MockProvider mockProvider = mMockProviders.get(provider);
1652            if (mockProvider == null) {
1653                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1654            }
1655            mockProvider.clearLocation();
1656        }
1657    }
1658
1659    @Override
1660    public void setTestProviderEnabled(String provider, boolean enabled) {
1661        checkMockPermissionsSafe();
1662        synchronized (mLock) {
1663            MockProvider mockProvider = mMockProviders.get(provider);
1664            if (mockProvider == null) {
1665                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1666            }
1667            long identity = Binder.clearCallingIdentity();
1668            if (enabled) {
1669                mockProvider.enable();
1670                mEnabledProviders.add(provider);
1671                mDisabledProviders.remove(provider);
1672            } else {
1673                mockProvider.disable();
1674                mEnabledProviders.remove(provider);
1675                mDisabledProviders.add(provider);
1676            }
1677            updateProvidersLocked();
1678            Binder.restoreCallingIdentity(identity);
1679        }
1680    }
1681
1682    @Override
1683    public void clearTestProviderEnabled(String provider) {
1684        checkMockPermissionsSafe();
1685        synchronized (mLock) {
1686            MockProvider mockProvider = mMockProviders.get(provider);
1687            if (mockProvider == null) {
1688                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1689            }
1690            long identity = Binder.clearCallingIdentity();
1691            mEnabledProviders.remove(provider);
1692            mDisabledProviders.remove(provider);
1693            updateProvidersLocked();
1694            Binder.restoreCallingIdentity(identity);
1695        }
1696    }
1697
1698    @Override
1699    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1700        checkMockPermissionsSafe();
1701        synchronized (mLock) {
1702            MockProvider mockProvider = mMockProviders.get(provider);
1703            if (mockProvider == null) {
1704                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1705            }
1706            mockProvider.setStatus(status, extras, updateTime);
1707        }
1708    }
1709
1710    @Override
1711    public void clearTestProviderStatus(String provider) {
1712        checkMockPermissionsSafe();
1713        synchronized (mLock) {
1714            MockProvider mockProvider = mMockProviders.get(provider);
1715            if (mockProvider == null) {
1716                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1717            }
1718            mockProvider.clearStatus();
1719        }
1720    }
1721
1722    private void log(String log) {
1723        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1724            Slog.d(TAG, log);
1725        }
1726    }
1727
1728    @Override
1729    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1730        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1731                != PackageManager.PERMISSION_GRANTED) {
1732            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
1733                    + Binder.getCallingPid()
1734                    + ", uid=" + Binder.getCallingUid());
1735            return;
1736        }
1737
1738        synchronized (mLock) {
1739            pw.println("Current Location Manager state:");
1740            pw.println("  Location Listeners:");
1741            for (Receiver receiver : mReceivers.values()) {
1742                pw.println("    " + receiver);
1743            }
1744            pw.println("  Records by Provider:");
1745            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1746                pw.println("    " + entry.getKey() + ":");
1747                for (UpdateRecord record : entry.getValue()) {
1748                    pw.println("      " + record);
1749                }
1750            }
1751            pw.println("  Last Known Locations:");
1752            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1753                String provider = entry.getKey();
1754                Location location = entry.getValue();
1755                pw.println("    " + provider + ": " + location);
1756            }
1757
1758            mGeofenceManager.dump(pw);
1759
1760            if (mEnabledProviders.size() > 0) {
1761                pw.println("  Enabled Providers:");
1762                for (String i : mEnabledProviders) {
1763                    pw.println("    " + i);
1764                }
1765
1766            }
1767            if (mDisabledProviders.size() > 0) {
1768                pw.println("  Disabled Providers:");
1769                for (String i : mDisabledProviders) {
1770                    pw.println("    " + i);
1771                }
1772            }
1773            pw.append("  ");
1774            mBlacklist.dump(pw);
1775            if (mMockProviders.size() > 0) {
1776                pw.println("  Mock Providers:");
1777                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
1778                    i.getValue().dump(pw, "      ");
1779                }
1780            }
1781
1782            pw.append("  fudger: ");
1783            mLocationFudger.dump(fd, pw,  args);
1784
1785            if (args.length > 0 && "short".equals(args[0])) {
1786                return;
1787            }
1788            for (LocationProviderInterface provider: mProviders) {
1789                pw.print(provider.getName() + " Internal State");
1790                if (provider instanceof LocationProviderProxy) {
1791                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
1792                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
1793                }
1794                pw.println(":");
1795                provider.dump(fd, pw, args);
1796            }
1797        }
1798    }
1799}
1800