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