LocationManagerService.java revision 74fa7eabda3d0c1a85e0b568e3fc4230ed4fe7a4
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import android.app.PendingIntent;
20import android.content.ContentQueryMap;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.content.pm.ApplicationInfo;
26import android.content.pm.PackageManager;
27import android.content.pm.PackageManager.NameNotFoundException;
28import android.content.res.Resources;
29import android.database.Cursor;
30import android.location.Address;
31import android.location.Criteria;
32import android.location.GeocoderParams;
33import android.location.Geofence;
34import android.location.IGpsStatusListener;
35import android.location.IGpsStatusProvider;
36import android.location.ILocationListener;
37import android.location.ILocationManager;
38import android.location.INetInitiatedListener;
39import android.location.Location;
40import android.location.LocationManager;
41import android.location.LocationProvider;
42import android.location.LocationRequest;
43import android.net.ConnectivityManager;
44import android.os.Binder;
45import android.os.Bundle;
46import android.os.Handler;
47import android.os.IBinder;
48import android.os.Looper;
49import android.os.Message;
50import android.os.PowerManager;
51import android.os.Process;
52import android.os.RemoteException;
53import android.os.SystemClock;
54import android.os.WorkSource;
55import android.provider.Settings;
56import android.provider.Settings.NameValueTable;
57import android.util.Log;
58import android.util.Slog;
59
60import com.android.internal.content.PackageMonitor;
61import com.android.internal.location.ProviderProperties;
62import com.android.internal.location.ProviderRequest;
63import com.android.server.location.GeocoderProxy;
64import com.android.server.location.GeofenceManager;
65import com.android.server.location.GpsLocationProvider;
66import com.android.server.location.LocationFudger;
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    // Location Providers may sometimes deliver location updates
114    // slightly faster that requested - provide grace period so
115    // we don't unnecessarily filter events that are otherwise on
116    // time
117    private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
118
119    private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
120
121    private final Context mContext;
122
123    // used internally for synchronization
124    private final Object mLock = new Object();
125
126    // --- fields below are final after init() ---
127    private LocationFudger mLocationFudger;
128    private GeofenceManager mGeofenceManager;
129    private PowerManager.WakeLock mWakeLock;
130    private PackageManager mPackageManager;
131    private GeocoderProxy mGeocodeProvider;
132    private IGpsStatusProvider mGpsStatusProvider;
133    private INetInitiatedListener mNetInitiatedListener;
134    private LocationWorkerHandler mLocationHandler;
135    // track the passive provider for some special cases
136    private PassiveProvider mPassiveProvider;
137
138    // --- fields below are protected by mWakeLock ---
139    private int mPendingBroadcasts;
140
141    // --- fields below are protected by mLock ---
142    // Set of providers that are explicitly enabled
143    private final Set<String> mEnabledProviders = new HashSet<String>();
144
145    // Set of providers that are explicitly disabled
146    private final Set<String> mDisabledProviders = new HashSet<String>();
147
148    // Mock (test) providers
149    private final HashMap<String, MockProvider> mMockProviders =
150            new HashMap<String, MockProvider>();
151
152    // all receivers
153    private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
154
155    // currently installed providers (with mocks replacing real providers)
156    private final ArrayList<LocationProviderInterface> mProviders =
157            new ArrayList<LocationProviderInterface>();
158
159    // real providers, saved here when mocked out
160    private final HashMap<String, LocationProviderInterface> mRealProviders =
161            new HashMap<String, LocationProviderInterface>();
162
163    // mapping from provider name to provider
164    private final HashMap<String, LocationProviderInterface> mProvidersByName =
165            new HashMap<String, LocationProviderInterface>();
166
167    // mapping from provider name to all its UpdateRecords
168    private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
169            new HashMap<String, ArrayList<UpdateRecord>>();
170
171    // mapping from provider name to last known location
172    private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
173
174    // all providers that operate over proxy, for authorizing incoming location
175    private final ArrayList<LocationProviderProxy> mProxyProviders =
176            new ArrayList<LocationProviderProxy>();
177
178    public LocationManagerService(Context context) {
179        super();
180        mContext = context;
181
182        if (D) Log.d(TAG, "Constructed");
183
184        // most startup is deferred until systemReady()
185    }
186
187    public void systemReady() {
188        Thread thread = new Thread(null, this, THREAD_NAME);
189        thread.start();
190    }
191
192    @Override
193    public void run() {
194        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
195        Looper.prepare();
196        mLocationHandler = new LocationWorkerHandler();
197        init();
198        Looper.loop();
199    }
200
201    private void init() {
202        if (D) Log.d(TAG, "init()");
203
204        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
205        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
206        mPackageManager = mContext.getPackageManager();
207
208        synchronized (mLock) {
209            loadProvidersLocked();
210        }
211        mGeofenceManager = new GeofenceManager(mContext);
212        mLocationFudger = new LocationFudger();
213
214        // Register for Network (Wifi or Mobile) updates
215        IntentFilter filter = new IntentFilter();
216        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
217
218        // listen for settings changes
219        ContentResolver resolver = mContext.getContentResolver();
220        Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
221                "(" + NameValueTable.NAME + "=?)",
222                new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, null);
223        ContentQueryMap query = new ContentQueryMap(settingsCursor, NameValueTable.NAME, true,
224                mLocationHandler);
225        settingsCursor.close();
226        query.addObserver(this);
227        mPackageMonitor.register(mContext, Looper.myLooper(), true);
228    }
229
230    private void loadProvidersLocked() {
231        if (GpsLocationProvider.isSupported()) {
232            // Create a gps location provider
233            GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
234            mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
235            mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
236            addProviderLocked(gpsProvider);
237            mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
238        }
239
240        // create a passive location provider, which is always enabled
241        PassiveProvider passiveProvider = new PassiveProvider(this);
242        addProviderLocked(passiveProvider);
243        mEnabledProviders.add(passiveProvider.getName());
244        mPassiveProvider = passiveProvider;
245
246        /*
247        Load package name(s) containing location provider support.
248        These packages can contain services implementing location providers:
249        Geocoder Provider, Network Location Provider, and
250        Fused Location Provider. They will each be searched for
251        service components implementing these providers.
252        The location framework also has support for installation
253        of new location providers at run-time. The new package does not
254        have to be explicitly listed here, however it must have a signature
255        that matches the signature of at least one package on this list.
256        */
257        Resources resources = mContext.getResources();
258        ArrayList<String> providerPackageNames = new ArrayList<String>();
259        String[] pkgs1 = resources.getStringArray(
260                com.android.internal.R.array.config_locationProviderPackageNames);
261        String[] pkgs2 = resources.getStringArray(
262                com.android.internal.R.array.config_overlay_locationProviderPackageNames);
263        if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
264        if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
265        if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
266        if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
267
268        // bind to network provider
269        LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
270                mContext,
271                LocationManager.NETWORK_PROVIDER,
272                NETWORK_LOCATION_SERVICE_ACTION,
273                providerPackageNames, mLocationHandler);
274        if (networkProvider != null) {
275            mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
276            mProxyProviders.add(networkProvider);
277            addProviderLocked(networkProvider);
278        } else {
279            Slog.w(TAG,  "no network location provider found");
280        }
281
282        // bind to fused provider
283        LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
284                mContext,
285                LocationManager.FUSED_PROVIDER,
286                FUSED_LOCATION_SERVICE_ACTION,
287                providerPackageNames, mLocationHandler);
288        if (fusedLocationProvider != null) {
289            addProviderLocked(fusedLocationProvider);
290            mProxyProviders.add(fusedLocationProvider);
291            mEnabledProviders.add(fusedLocationProvider.getName());
292        } else {
293            Slog.e(TAG, "no fused location provider found",
294                    new IllegalStateException("Location service needs a fused location provider"));
295        }
296
297        // bind to geocoder provider
298        mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
299        if (mGeocodeProvider == null) {
300            Slog.e(TAG,  "no geocoder provider found");
301        }
302
303        updateProvidersLocked();
304    }
305
306    /**
307     * A wrapper class holding either an ILocationListener or a PendingIntent to receive
308     * location updates.
309     */
310    private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
311        final int mUid;  // uid of receiver
312        final int mPid;  // pid of receiver
313        final String mPackageName;  // package name of receiver
314        final String mPermission;  // best permission that receiver has
315
316        final ILocationListener mListener;
317        final PendingIntent mPendingIntent;
318        final Object mKey;
319
320        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
321
322        int mPendingBroadcasts;
323
324        Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
325                String packageName) {
326            mListener = listener;
327            mPendingIntent = intent;
328            if (listener != null) {
329                mKey = listener.asBinder();
330            } else {
331                mKey = intent;
332            }
333            mPermission = checkPermission();
334            mUid = uid;
335            mPid = pid;
336            mPackageName = packageName;
337        }
338
339        @Override
340        public boolean equals(Object otherObj) {
341            if (otherObj instanceof Receiver) {
342                return mKey.equals(((Receiver)otherObj).mKey);
343            }
344            return false;
345        }
346
347        @Override
348        public int hashCode() {
349            return mKey.hashCode();
350        }
351
352        @Override
353        public String toString() {
354            StringBuilder s = new StringBuilder();
355            s.append("Reciever[");
356            s.append(Integer.toHexString(System.identityHashCode(this)));
357            if (mListener != null) {
358                s.append(" listener");
359            } else {
360                s.append(" intent");
361            }
362            for (String p : mUpdateRecords.keySet()) {
363                s.append(" ").append(mUpdateRecords.get(p).toString());
364            }
365            s.append("]");
366            return s.toString();
367        }
368
369        public boolean isListener() {
370            return mListener != null;
371        }
372
373        public boolean isPendingIntent() {
374            return mPendingIntent != null;
375        }
376
377        public ILocationListener getListener() {
378            if (mListener != null) {
379                return mListener;
380            }
381            throw new IllegalStateException("Request for non-existent listener");
382        }
383
384        public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
385            if (mListener != null) {
386                try {
387                    synchronized (this) {
388                        // synchronize to ensure incrementPendingBroadcastsLocked()
389                        // is called before decrementPendingBroadcasts()
390                        mListener.onStatusChanged(provider, status, extras);
391                        // call this after broadcasting so we do not increment
392                        // if we throw an exeption.
393                        incrementPendingBroadcastsLocked();
394                    }
395                } catch (RemoteException e) {
396                    return false;
397                }
398            } else {
399                Intent statusChanged = new Intent();
400                statusChanged.putExtras(extras);
401                statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
402                try {
403                    synchronized (this) {
404                        // synchronize to ensure incrementPendingBroadcastsLocked()
405                        // is called before decrementPendingBroadcasts()
406                        mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
407                                mPermission);
408                        // call this after broadcasting so we do not increment
409                        // if we throw an exeption.
410                        incrementPendingBroadcastsLocked();
411                    }
412                } catch (PendingIntent.CanceledException e) {
413                    return false;
414                }
415            }
416            return true;
417        }
418
419        public boolean callLocationChangedLocked(Location location) {
420            if (mListener != null) {
421                try {
422                    synchronized (this) {
423                        // synchronize to ensure incrementPendingBroadcastsLocked()
424                        // is called before decrementPendingBroadcasts()
425                        mListener.onLocationChanged(location);
426                        // call this after broadcasting so we do not increment
427                        // if we throw an exeption.
428                        incrementPendingBroadcastsLocked();
429                    }
430                } catch (RemoteException e) {
431                    return false;
432                }
433            } else {
434                Intent locationChanged = new Intent();
435                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
436                try {
437                    synchronized (this) {
438                        // synchronize to ensure incrementPendingBroadcastsLocked()
439                        // is called before decrementPendingBroadcasts()
440                        mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
441                                mPermission);
442                        // call this after broadcasting so we do not increment
443                        // if we throw an exeption.
444                        incrementPendingBroadcastsLocked();
445                    }
446                } catch (PendingIntent.CanceledException e) {
447                    return false;
448                }
449            }
450            return true;
451        }
452
453        public boolean callProviderEnabledLocked(String provider, boolean enabled) {
454            if (mListener != null) {
455                try {
456                    synchronized (this) {
457                        // synchronize to ensure incrementPendingBroadcastsLocked()
458                        // is called before decrementPendingBroadcasts()
459                        if (enabled) {
460                            mListener.onProviderEnabled(provider);
461                        } else {
462                            mListener.onProviderDisabled(provider);
463                        }
464                        // call this after broadcasting so we do not increment
465                        // if we throw an exeption.
466                        incrementPendingBroadcastsLocked();
467                    }
468                } catch (RemoteException e) {
469                    return false;
470                }
471            } else {
472                Intent providerIntent = new Intent();
473                providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
474                try {
475                    synchronized (this) {
476                        // synchronize to ensure incrementPendingBroadcastsLocked()
477                        // is called before decrementPendingBroadcasts()
478                        mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
479                                mPermission);
480                        // call this after broadcasting so we do not increment
481                        // if we throw an exeption.
482                        incrementPendingBroadcastsLocked();
483                    }
484                } catch (PendingIntent.CanceledException e) {
485                    return false;
486                }
487            }
488            return true;
489        }
490
491        @Override
492        public void binderDied() {
493            if (D) Log.d(TAG, "Location listener died");
494
495            synchronized (mLock) {
496                removeUpdatesLocked(this);
497            }
498            synchronized (this) {
499                if (mPendingBroadcasts > 0) {
500                    LocationManagerService.this.decrementPendingBroadcasts();
501                    mPendingBroadcasts = 0;
502                }
503            }
504        }
505
506        @Override
507        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
508                int resultCode, String resultData, Bundle resultExtras) {
509            synchronized (this) {
510                decrementPendingBroadcastsLocked();
511            }
512        }
513
514        // this must be called while synchronized by caller in a synchronized block
515        // containing the sending of the broadcaset
516        private void incrementPendingBroadcastsLocked() {
517            if (mPendingBroadcasts++ == 0) {
518                LocationManagerService.this.incrementPendingBroadcasts();
519            }
520        }
521
522        private void decrementPendingBroadcastsLocked() {
523            if (--mPendingBroadcasts == 0) {
524                LocationManagerService.this.decrementPendingBroadcasts();
525            }
526        }
527    }
528
529    @Override
530    public void locationCallbackFinished(ILocationListener listener) {
531        //Do not use getReceiver here as that will add the ILocationListener to
532        //the receiver list if it is not found.  If it is not found then the
533        //LocationListener was removed when it had a pending broadcast and should
534        //not be added back.
535        IBinder binder = listener.asBinder();
536        Receiver receiver = mReceivers.get(binder);
537        if (receiver != null) {
538            synchronized (receiver) {
539                // so wakelock calls will succeed
540                long identity = Binder.clearCallingIdentity();
541                receiver.decrementPendingBroadcastsLocked();
542                Binder.restoreCallingIdentity(identity);
543           }
544        }
545    }
546
547    /** Settings Observer callback */
548    @Override
549    public void update(Observable o, Object arg) {
550        synchronized (mLock) {
551            updateProvidersLocked();
552        }
553    }
554
555    private void addProviderLocked(LocationProviderInterface provider) {
556        mProviders.add(provider);
557        mProvidersByName.put(provider.getName(), provider);
558    }
559
560    private void removeProviderLocked(LocationProviderInterface provider) {
561        provider.disable();
562        mProviders.remove(provider);
563        mProvidersByName.remove(provider.getName());
564    }
565
566
567    private boolean isAllowedBySettingsLocked(String provider) {
568        if (mEnabledProviders.contains(provider)) {
569            return true;
570        }
571        if (mDisabledProviders.contains(provider)) {
572            return false;
573        }
574        // Use system settings
575        ContentResolver resolver = mContext.getContentResolver();
576
577        return Settings.Secure.isLocationProviderEnabled(resolver, provider);
578    }
579
580    /**
581     * Throw SecurityException if caller has neither COARSE or FINE.
582     * Otherwise, return the best permission.
583     */
584    private String checkPermission() {
585        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
586                PackageManager.PERMISSION_GRANTED) {
587            return ACCESS_FINE_LOCATION;
588        } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
589                PackageManager.PERMISSION_GRANTED) {
590            return ACCESS_COARSE_LOCATION;
591        }
592
593        throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
594                "ACCESS_FINE_LOCATION permission");
595    }
596
597    /**
598     * Returns all providers by name, including passive, but excluding
599     * fused.
600     */
601    @Override
602    public List<String> getAllProviders() {
603        checkPermission();
604
605        ArrayList<String> out;
606        synchronized (mLock) {
607            out = new ArrayList<String>(mProviders.size());
608            for (LocationProviderInterface provider : mProviders) {
609                String name = provider.getName();
610                if (LocationManager.FUSED_PROVIDER.equals(name)) {
611                    continue;
612                }
613                out.add(name);
614            }
615        }
616
617        if (D) Log.d(TAG, "getAllProviders()=" + out);
618        return out;
619    }
620
621    /**
622     * Return all providers by name, that match criteria and are optionally
623     * enabled.
624     * Can return passive provider, but never returns fused provider.
625     */
626    @Override
627    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
628        checkPermission();
629
630        ArrayList<String> out;
631        synchronized (mLock) {
632            out = new ArrayList<String>(mProviders.size());
633            for (LocationProviderInterface provider : mProviders) {
634                String name = provider.getName();
635                if (LocationManager.FUSED_PROVIDER.equals(name)) {
636                    continue;
637                }
638                if (enabledOnly && !isAllowedBySettingsLocked(name)) {
639                    continue;
640                }
641                if (criteria != null && !LocationProvider.propertiesMeetCriteria(
642                        name, provider.getProperties(), criteria)) {
643                    continue;
644                }
645                out.add(name);
646            }
647        }
648
649        if (D) Log.d(TAG, "getProviders()=" + out);
650        return out;
651    }
652
653    /**
654     * Return the name of the best provider given a Criteria object.
655     * This method has been deprecated from the public API,
656     * and the whole LoactionProvider (including #meetsCriteria)
657     * has been deprecated as well. So this method now uses
658     * some simplified logic.
659     */
660    @Override
661    public String getBestProvider(Criteria criteria, boolean enabledOnly) {
662        String result = null;
663        checkPermission();
664
665        List<String> providers = getProviders(criteria, enabledOnly);
666        if (providers.size() < 1) {
667            result = pickBest(providers);
668            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
669            return result;
670        }
671        providers = getProviders(null, enabledOnly);
672        if (providers.size() >= 1) {
673            result = pickBest(providers);
674            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
675            return result;
676        }
677
678        if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
679        return null;
680    }
681
682    private String pickBest(List<String> providers) {
683        if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
684            return LocationManager.NETWORK_PROVIDER;
685        } else if (providers.contains(LocationManager.GPS_PROVIDER)) {
686            return LocationManager.GPS_PROVIDER;
687        } else {
688            return providers.get(0);
689        }
690    }
691
692    @Override
693    public boolean providerMeetsCriteria(String provider, Criteria criteria) {
694        checkPermission();
695
696        LocationProviderInterface p = mProvidersByName.get(provider);
697        if (p == null) {
698            throw new IllegalArgumentException("provider=" + provider);
699        }
700
701        boolean result = LocationProvider.propertiesMeetCriteria(
702                p.getName(), p.getProperties(), criteria);
703        if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
704        return result;
705    }
706
707    private void updateProvidersLocked() {
708        boolean changesMade = false;
709        for (int i = mProviders.size() - 1; i >= 0; i--) {
710            LocationProviderInterface p = mProviders.get(i);
711            boolean isEnabled = p.isEnabled();
712            String name = p.getName();
713            boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
714            if (isEnabled && !shouldBeEnabled) {
715                updateProviderListenersLocked(name, false);
716                changesMade = true;
717            } else if (!isEnabled && shouldBeEnabled) {
718                updateProviderListenersLocked(name, true);
719                changesMade = true;
720            }
721        }
722        if (changesMade) {
723            mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
724        }
725    }
726
727    private void updateProviderListenersLocked(String provider, boolean enabled) {
728        int listeners = 0;
729
730        LocationProviderInterface p = mProvidersByName.get(provider);
731        if (p == null) return;
732
733        ArrayList<Receiver> deadReceivers = null;
734
735        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
736        if (records != null) {
737            final int N = records.size();
738            for (int i = 0; i < N; i++) {
739                UpdateRecord record = records.get(i);
740                // Sends a notification message to the receiver
741                if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
742                    if (deadReceivers == null) {
743                        deadReceivers = new ArrayList<Receiver>();
744                    }
745                    deadReceivers.add(record.mReceiver);
746                }
747                listeners++;
748            }
749        }
750
751        if (deadReceivers != null) {
752            for (int i = deadReceivers.size() - 1; i >= 0; i--) {
753                removeUpdatesLocked(deadReceivers.get(i));
754            }
755        }
756
757        if (enabled) {
758            p.enable();
759            if (listeners > 0) {
760                applyRequirementsLocked(provider);
761            }
762        } else {
763            p.disable();
764        }
765    }
766
767    private void applyRequirementsLocked(String provider) {
768        LocationProviderInterface p = mProvidersByName.get(provider);
769        if (p == null) return;
770
771        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
772        WorkSource worksource = new WorkSource();
773        ProviderRequest providerRequest = new ProviderRequest();
774
775        if (records != null) {
776            for (UpdateRecord record : records) {
777                LocationRequest locationRequest = record.mRequest;
778
779                providerRequest.locationRequests.add(locationRequest);
780                if (locationRequest.getInterval() < providerRequest.interval) {
781                    providerRequest.reportLocation = true;
782                    providerRequest.interval = locationRequest.getInterval();
783                }
784            }
785
786            if (providerRequest.reportLocation) {
787                // calculate who to blame for power
788                // This is somewhat arbitrary. We pick a threshold interval
789                // that is slightly higher that the minimum interval, and
790                // spread the blame across all applications with a request
791                // under that threshold.
792                long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
793                for (UpdateRecord record : records) {
794                    LocationRequest locationRequest = record.mRequest;
795                    if (locationRequest.getInterval() <= thresholdInterval) {
796                        worksource.add(record.mReceiver.mUid);
797                    }
798                }
799            }
800        }
801
802        if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
803        p.setRequest(providerRequest, worksource);
804    }
805
806    private class UpdateRecord {
807        final String mProvider;
808        final LocationRequest mRequest;
809        final Receiver mReceiver;
810        Location mLastFixBroadcast;
811        long mLastStatusBroadcast;
812
813        /**
814         * Note: must be constructed with lock held.
815         */
816        UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
817            mProvider = provider;
818            mRequest = request;
819            mReceiver = receiver;
820
821            ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
822            if (records == null) {
823                records = new ArrayList<UpdateRecord>();
824                mRecordsByProvider.put(provider, records);
825            }
826            if (!records.contains(this)) {
827                records.add(this);
828            }
829        }
830
831        /**
832         * Method to be called when a record will no longer be used.  Calling this multiple times
833         * must have the same effect as calling it once.
834         */
835        void disposeLocked(boolean removeReceiver) {
836            // remove from mRecordsByProvider
837            ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
838            if (globalRecords != null) {
839                globalRecords.remove(this);
840            }
841
842            if (!removeReceiver) return;  // the caller will handle the rest
843
844            // remove from Receiver#mUpdateRecords
845            HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
846            if (receiverRecords != null) {
847                receiverRecords.remove(this.mProvider);
848
849                // and also remove the Receiver if it has no more update records
850                if (removeReceiver && receiverRecords.size() == 0) {
851                    removeUpdatesLocked(mReceiver);
852                }
853            }
854        }
855
856        @Override
857        public String toString() {
858            StringBuilder s = new StringBuilder();
859            s.append("UpdateRecord[");
860            s.append(mProvider);
861            s.append(' ').append(mReceiver.mPackageName).append('(');
862            s.append(mReceiver.mUid).append(')');
863            s.append(' ').append(mRequest);
864            s.append(']');
865            return s.toString();
866        }
867    }
868
869    private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
870        IBinder binder = listener.asBinder();
871        Receiver receiver = mReceivers.get(binder);
872        if (receiver == null) {
873            receiver = new Receiver(listener, null, pid, uid, packageName);
874            mReceivers.put(binder, receiver);
875
876            try {
877                receiver.getListener().asBinder().linkToDeath(receiver, 0);
878            } catch (RemoteException e) {
879                Slog.e(TAG, "linkToDeath failed:", e);
880                return null;
881            }
882        }
883        return receiver;
884    }
885
886    private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
887        Receiver receiver = mReceivers.get(intent);
888        if (receiver == null) {
889            receiver = new Receiver(null, intent, pid, uid, packageName);
890            mReceivers.put(intent, receiver);
891        }
892        return receiver;
893    }
894
895    private String checkPermissionAndRequest(LocationRequest request) {
896        String perm = checkPermission();
897
898        if (ACCESS_COARSE_LOCATION.equals(perm)) {
899             switch (request.getQuality()) {
900                 case LocationRequest.ACCURACY_FINE:
901                     request.setQuality(LocationRequest.ACCURACY_BLOCK);
902                     break;
903                 case LocationRequest.POWER_HIGH:
904                     request.setQuality(LocationRequest.POWER_LOW);
905                     break;
906             }
907             // throttle fastest interval
908             if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
909                 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
910             }
911        }
912        // throttle interval if its faster than the fastest interval
913        if (request.getInterval () < request.getFastestInterval()) {
914            request.setInterval(request.getFastestInterval());
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 mLocationFudger.getOrCreate(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
1299        Location coarse = mLocationFudger.getOrCreate(location);
1300
1301        // Update last known locations
1302        Location lastLocation = mLastLocation.get(provider);
1303        if (lastLocation == null) {
1304            lastLocation = new Location(provider);
1305            mLastLocation.put(provider, lastLocation);
1306        }
1307        lastLocation.set(location);
1308
1309        // Fetch latest status update time
1310        long newStatusUpdateTime = p.getStatusUpdateTime();
1311
1312       // Get latest status
1313        Bundle extras = new Bundle();
1314        int status = p.getStatus(extras);
1315
1316        ArrayList<Receiver> deadReceivers = null;
1317        ArrayList<UpdateRecord> deadUpdateRecords = null;
1318
1319        // Broadcast location or status to all listeners
1320        for (UpdateRecord r : records) {
1321            Receiver receiver = r.mReceiver;
1322            boolean receiverDead = false;
1323            if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1324                location = lastLocation;  // use fine location
1325            } else {
1326                location = coarse;  // use coarse location
1327            }
1328
1329            Location lastLoc = r.mLastFixBroadcast;
1330            if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1331                if (lastLoc == null) {
1332                    lastLoc = new Location(location);
1333                    r.mLastFixBroadcast = lastLoc;
1334                } else {
1335                    lastLoc.set(location);
1336                }
1337                if (!receiver.callLocationChangedLocked(location)) {
1338                    Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1339                    receiverDead = true;
1340                }
1341            }
1342
1343            long prevStatusUpdateTime = r.mLastStatusBroadcast;
1344            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1345                (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1346
1347                r.mLastStatusBroadcast = newStatusUpdateTime;
1348                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1349                    receiverDead = true;
1350                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1351                }
1352            }
1353
1354            // track expired records
1355            if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1356                if (deadUpdateRecords == null) {
1357                    deadUpdateRecords = new ArrayList<UpdateRecord>();
1358                }
1359                deadUpdateRecords.add(r);
1360            }
1361            // track dead receivers
1362            if (receiverDead) {
1363                if (deadReceivers == null) {
1364                    deadReceivers = new ArrayList<Receiver>();
1365                }
1366                if (!deadReceivers.contains(receiver)) {
1367                    deadReceivers.add(receiver);
1368                }
1369            }
1370        }
1371
1372        // remove dead records and receivers outside the loop
1373        if (deadReceivers != null) {
1374            for (Receiver receiver : deadReceivers) {
1375                removeUpdatesLocked(receiver);
1376            }
1377        }
1378        if (deadUpdateRecords != null) {
1379            for (UpdateRecord r : deadUpdateRecords) {
1380                r.disposeLocked(true);
1381            }
1382        }
1383    }
1384
1385    private class LocationWorkerHandler extends Handler {
1386        @Override
1387        public void handleMessage(Message msg) {
1388            switch (msg.what) {
1389                case MSG_LOCATION_CHANGED:
1390                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1391                    break;
1392            }
1393        }
1394    }
1395
1396    private void handleLocationChanged(Location location, boolean passive) {
1397        String provider = location.getProvider();
1398
1399        if (!passive) {
1400            // notify passive provider of the new location
1401            mPassiveProvider.updateLocation(location);
1402        }
1403
1404        synchronized (mLock) {
1405            if (isAllowedBySettingsLocked(provider)) {
1406                handleLocationChangedLocked(location, passive);
1407            }
1408        }
1409    }
1410
1411    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1412        @Override
1413        public void onPackageDisappeared(String packageName, int reason) {
1414            // remove all receivers associated with this package name
1415            synchronized (mLock) {
1416                ArrayList<Receiver> deadReceivers = null;
1417
1418                for (Receiver receiver : mReceivers.values()) {
1419                    if (receiver.mPackageName.equals(packageName)) {
1420                        if (deadReceivers == null) {
1421                            deadReceivers = new ArrayList<Receiver>();
1422                        }
1423                        deadReceivers.add(receiver);
1424                    }
1425                }
1426
1427                // perform removal outside of mReceivers loop
1428                if (deadReceivers != null) {
1429                    for (Receiver receiver : deadReceivers) {
1430                        removeUpdatesLocked(receiver);
1431                    }
1432                }
1433            }
1434        }
1435    };
1436
1437    // Wake locks
1438
1439    private void incrementPendingBroadcasts() {
1440        synchronized (mWakeLock) {
1441            if (mPendingBroadcasts++ == 0) {
1442                try {
1443                    mWakeLock.acquire();
1444                    log("Acquired wakelock");
1445                } catch (Exception e) {
1446                    // This is to catch a runtime exception thrown when we try to release an
1447                    // already released lock.
1448                    Slog.e(TAG, "exception in acquireWakeLock()", e);
1449                }
1450            }
1451        }
1452    }
1453
1454    private void decrementPendingBroadcasts() {
1455        synchronized (mWakeLock) {
1456            if (--mPendingBroadcasts == 0) {
1457                try {
1458                    // Release wake lock
1459                    if (mWakeLock.isHeld()) {
1460                        mWakeLock.release();
1461                        log("Released wakelock");
1462                    } else {
1463                        log("Can't release wakelock again!");
1464                    }
1465                } catch (Exception e) {
1466                    // This is to catch a runtime exception thrown when we try to release an
1467                    // already released lock.
1468                    Slog.e(TAG, "exception in releaseWakeLock()", e);
1469                }
1470            }
1471        }
1472    }
1473
1474    // Geocoder
1475
1476    @Override
1477    public boolean geocoderIsPresent() {
1478        return mGeocodeProvider != null;
1479    }
1480
1481    @Override
1482    public String getFromLocation(double latitude, double longitude, int maxResults,
1483            GeocoderParams params, List<Address> addrs) {
1484        if (mGeocodeProvider != null) {
1485            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1486                    params, addrs);
1487        }
1488        return null;
1489    }
1490
1491
1492    @Override
1493    public String getFromLocationName(String locationName,
1494            double lowerLeftLatitude, double lowerLeftLongitude,
1495            double upperRightLatitude, double upperRightLongitude, int maxResults,
1496            GeocoderParams params, List<Address> addrs) {
1497
1498        if (mGeocodeProvider != null) {
1499            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1500                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1501                    maxResults, params, addrs);
1502        }
1503        return null;
1504    }
1505
1506    // Mock Providers
1507
1508    private void checkMockPermissionsSafe() {
1509        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1510                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1511        if (!allowMocks) {
1512            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1513        }
1514
1515        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1516            PackageManager.PERMISSION_GRANTED) {
1517            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1518        }
1519    }
1520
1521    @Override
1522    public void addTestProvider(String name, ProviderProperties properties) {
1523        checkMockPermissionsSafe();
1524
1525        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1526            throw new IllegalArgumentException("Cannot mock the passive location provider");
1527        }
1528
1529        long identity = Binder.clearCallingIdentity();
1530        synchronized (mLock) {
1531            MockProvider provider = new MockProvider(name, this, properties);
1532            // remove the real provider if we are replacing GPS or network provider
1533            if (LocationManager.GPS_PROVIDER.equals(name)
1534                    || LocationManager.NETWORK_PROVIDER.equals(name)) {
1535                LocationProviderInterface p = mProvidersByName.get(name);
1536                if (p != null) {
1537                    removeProviderLocked(p);
1538                }
1539            }
1540            if (mProvidersByName.get(name) != null) {
1541                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1542            }
1543            addProviderLocked(provider);
1544            mMockProviders.put(name, provider);
1545            mLastLocation.put(name, null);
1546            updateProvidersLocked();
1547        }
1548        Binder.restoreCallingIdentity(identity);
1549    }
1550
1551    @Override
1552    public void removeTestProvider(String provider) {
1553        checkMockPermissionsSafe();
1554        synchronized (mLock) {
1555            MockProvider mockProvider = mMockProviders.get(provider);
1556            if (mockProvider == null) {
1557                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1558            }
1559            long identity = Binder.clearCallingIdentity();
1560            removeProviderLocked(mProvidersByName.get(provider));
1561            mMockProviders.remove(mockProvider);
1562
1563            // reinstate real provider if available
1564            LocationProviderInterface realProvider = mRealProviders.get(provider);
1565            if (realProvider != null) {
1566                addProviderLocked(realProvider);
1567            }
1568            mLastLocation.put(provider, null);
1569            updateProvidersLocked();
1570            Binder.restoreCallingIdentity(identity);
1571        }
1572    }
1573
1574    @Override
1575    public void setTestProviderLocation(String provider, Location loc) {
1576        checkMockPermissionsSafe();
1577        synchronized (mLock) {
1578            MockProvider mockProvider = mMockProviders.get(provider);
1579            if (mockProvider == null) {
1580                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1581            }
1582            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1583            long identity = Binder.clearCallingIdentity();
1584            mockProvider.setLocation(loc);
1585            Binder.restoreCallingIdentity(identity);
1586        }
1587    }
1588
1589    @Override
1590    public void clearTestProviderLocation(String provider) {
1591        checkMockPermissionsSafe();
1592        synchronized (mLock) {
1593            MockProvider mockProvider = mMockProviders.get(provider);
1594            if (mockProvider == null) {
1595                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1596            }
1597            mockProvider.clearLocation();
1598        }
1599    }
1600
1601    @Override
1602    public void setTestProviderEnabled(String provider, boolean enabled) {
1603        checkMockPermissionsSafe();
1604        synchronized (mLock) {
1605            MockProvider mockProvider = mMockProviders.get(provider);
1606            if (mockProvider == null) {
1607                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1608            }
1609            long identity = Binder.clearCallingIdentity();
1610            if (enabled) {
1611                mockProvider.enable();
1612                mEnabledProviders.add(provider);
1613                mDisabledProviders.remove(provider);
1614            } else {
1615                mockProvider.disable();
1616                mEnabledProviders.remove(provider);
1617                mDisabledProviders.add(provider);
1618            }
1619            updateProvidersLocked();
1620            Binder.restoreCallingIdentity(identity);
1621        }
1622    }
1623
1624    @Override
1625    public void clearTestProviderEnabled(String provider) {
1626        checkMockPermissionsSafe();
1627        synchronized (mLock) {
1628            MockProvider mockProvider = mMockProviders.get(provider);
1629            if (mockProvider == null) {
1630                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1631            }
1632            long identity = Binder.clearCallingIdentity();
1633            mEnabledProviders.remove(provider);
1634            mDisabledProviders.remove(provider);
1635            updateProvidersLocked();
1636            Binder.restoreCallingIdentity(identity);
1637        }
1638    }
1639
1640    @Override
1641    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1642        checkMockPermissionsSafe();
1643        synchronized (mLock) {
1644            MockProvider mockProvider = mMockProviders.get(provider);
1645            if (mockProvider == null) {
1646                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1647            }
1648            mockProvider.setStatus(status, extras, updateTime);
1649        }
1650    }
1651
1652    @Override
1653    public void clearTestProviderStatus(String provider) {
1654        checkMockPermissionsSafe();
1655        synchronized (mLock) {
1656            MockProvider mockProvider = mMockProviders.get(provider);
1657            if (mockProvider == null) {
1658                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1659            }
1660            mockProvider.clearStatus();
1661        }
1662    }
1663
1664    private void log(String log) {
1665        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1666            Slog.d(TAG, log);
1667        }
1668    }
1669
1670    @Override
1671    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1672        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1673                != PackageManager.PERMISSION_GRANTED) {
1674            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
1675                    + Binder.getCallingPid()
1676                    + ", uid=" + Binder.getCallingUid());
1677            return;
1678        }
1679
1680        synchronized (mLock) {
1681            pw.println("Current Location Manager state:");
1682            pw.println("  Location Listeners:");
1683            for (Receiver receiver : mReceivers.values()) {
1684                pw.println("    " + receiver);
1685            }
1686            pw.println("  Records by Provider:");
1687            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1688                pw.println("    " + entry.getKey() + ":");
1689                for (UpdateRecord record : entry.getValue()) {
1690                    pw.println("      " + record);
1691                }
1692            }
1693            pw.println("  Last Known Locations:");
1694            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1695                String provider = entry.getKey();
1696                Location location = entry.getValue();
1697                pw.println("    " + provider + ": " + location);
1698            }
1699
1700            mGeofenceManager.dump(pw);
1701
1702            if (mEnabledProviders.size() > 0) {
1703                pw.println("  Enabled Providers:");
1704                for (String i : mEnabledProviders) {
1705                    pw.println("    " + i);
1706                }
1707
1708            }
1709            if (mDisabledProviders.size() > 0) {
1710                pw.println("  Disabled Providers:");
1711                for (String i : mDisabledProviders) {
1712                    pw.println("    " + i);
1713                }
1714
1715            }
1716            if (mMockProviders.size() > 0) {
1717                pw.println("  Mock Providers:");
1718                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
1719                    i.getValue().dump(pw, "      ");
1720                }
1721            }
1722
1723            pw.append("  fudger: ");
1724            mLocationFudger.dump(fd, pw,  args);
1725
1726            if (args.length > 0 && "short".equals(args[0])) {
1727                return;
1728            }
1729            for (LocationProviderInterface provider: mProviders) {
1730                pw.print(provider.getName() + " Internal State");
1731                if (provider instanceof LocationProviderProxy) {
1732                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
1733                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
1734                }
1735                pw.println(":");
1736                provider.dump(fd, pw, args);
1737            }
1738        }
1739    }
1740}
1741