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