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