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