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