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