LocationManagerService.java revision da479c5f8c9675dc11b3d6c4024749064d54bb67
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        checkPermissionForProvider(getBestCallingPermission(), provider);
1344
1345        LocationProviderInterface p;
1346        synchronized (mLock) {
1347            p = mProvidersByName.get(provider);
1348        }
1349
1350        if (p == null) return null;
1351        return p.getProperties();
1352    }
1353
1354    @Override
1355    public boolean isProviderEnabled(String provider) {
1356        checkPermissionForProvider(getBestCallingPermission(), provider);
1357        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1358
1359        long identity = Binder.clearCallingIdentity();
1360        try {
1361            synchronized (mLock) {
1362                LocationProviderInterface p = mProvidersByName.get(provider);
1363                if (p == null) return false;
1364
1365                return isAllowedBySettingsLocked(provider, mCurrentUserId);
1366            }
1367        } finally {
1368            Binder.restoreCallingIdentity(identity);
1369        }
1370    }
1371
1372    private void checkCallerIsProvider() {
1373        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1374                == PackageManager.PERMISSION_GRANTED) {
1375            return;
1376        }
1377
1378        // Previously we only used the INSTALL_LOCATION_PROVIDER
1379        // check. But that is system or signature
1380        // protection level which is not flexible enough for
1381        // providers installed oustide the system image. So
1382        // also allow providers with a UID matching the
1383        // currently bound package name
1384
1385        int uid = Binder.getCallingUid();
1386
1387        if (mGeocodeProvider != null) {
1388            if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1389        }
1390        for (LocationProviderProxy proxy : mProxyProviders) {
1391            if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1392        }
1393        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1394                "or UID of a currently bound location provider");
1395    }
1396
1397    private boolean doesPackageHaveUid(int uid, String packageName) {
1398        if (packageName == null) {
1399            return false;
1400        }
1401        try {
1402            ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1403            if (appInfo.uid != uid) {
1404                return false;
1405            }
1406        } catch (NameNotFoundException e) {
1407            return false;
1408        }
1409        return true;
1410    }
1411
1412    @Override
1413    public void reportLocation(Location location, boolean passive) {
1414        checkCallerIsProvider();
1415
1416        if (!location.isComplete()) {
1417            Log.w(TAG, "Dropping incomplete location: " + location);
1418            return;
1419        }
1420
1421        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1422        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
1423        m.arg1 = (passive ? 1 : 0);
1424        mLocationHandler.sendMessageAtFrontOfQueue(m);
1425    }
1426
1427
1428    private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1429        // Always broadcast the first update
1430        if (lastLoc == null) {
1431            return true;
1432        }
1433
1434        // Check whether sufficient time has passed
1435        long minTime = record.mRequest.getFastestInterval();
1436        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
1437        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
1438            return false;
1439        }
1440
1441        // Check whether sufficient distance has been traveled
1442        double minDistance = record.mRequest.getSmallestDisplacement();
1443        if (minDistance > 0.0) {
1444            if (loc.distanceTo(lastLoc) <= minDistance) {
1445                return false;
1446            }
1447        }
1448
1449        return true;
1450    }
1451
1452    private void handleLocationChangedLocked(Location location, boolean passive) {
1453        if (D) Log.d(TAG, "incoming location: " + location);
1454
1455        long now = SystemClock.elapsedRealtime();
1456        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
1457
1458        // Skip if the provider is unknown.
1459        LocationProviderInterface p = mProvidersByName.get(provider);
1460        if (p == null) return;
1461
1462        // Update last known locations
1463        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1464        Location lastNoGPSLocation = null;
1465        Location lastLocation = mLastLocation.get(provider);
1466        if (lastLocation == null) {
1467            lastLocation = new Location(provider);
1468            mLastLocation.put(provider, lastLocation);
1469        } else {
1470            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1471            if (noGPSLocation == null && lastNoGPSLocation != null) {
1472                // New location has no no-GPS location: adopt last no-GPS location. This is set
1473                // directly into location because we do not want to notify COARSE clients.
1474                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1475            }
1476        }
1477        lastLocation.set(location);
1478
1479        // Skip if there are no UpdateRecords for this provider.
1480        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1481        if (records == null || records.size() == 0) return;
1482
1483        // Fetch coarse location
1484        Location coarseLocation = null;
1485        if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1486            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1487        }
1488
1489        // Fetch latest status update time
1490        long newStatusUpdateTime = p.getStatusUpdateTime();
1491
1492       // Get latest status
1493        Bundle extras = new Bundle();
1494        int status = p.getStatus(extras);
1495
1496        ArrayList<Receiver> deadReceivers = null;
1497        ArrayList<UpdateRecord> deadUpdateRecords = null;
1498
1499        // Broadcast location or status to all listeners
1500        for (UpdateRecord r : records) {
1501            Receiver receiver = r.mReceiver;
1502            boolean receiverDead = false;
1503
1504            int receiverUserId = UserHandle.getUserId(receiver.mUid);
1505            if (receiverUserId != mCurrentUserId) {
1506                if (D) {
1507                    Log.d(TAG, "skipping loc update for background user " + receiverUserId +
1508                            " (current user: " + mCurrentUserId + ", app: " +
1509                            receiver.mPackageName + ")");
1510                }
1511                continue;
1512            }
1513
1514            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1515                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1516                        receiver.mPackageName);
1517                continue;
1518            }
1519
1520            Location notifyLocation = null;
1521            if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1522                notifyLocation = lastLocation;  // use fine location
1523            } else {
1524                notifyLocation = coarseLocation;  // use coarse location if available
1525            }
1526            if (notifyLocation != null) {
1527                Location lastLoc = r.mLastFixBroadcast;
1528                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1529                    if (lastLoc == null) {
1530                        lastLoc = new Location(notifyLocation);
1531                        r.mLastFixBroadcast = lastLoc;
1532                    } else {
1533                        lastLoc.set(notifyLocation);
1534                    }
1535                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
1536                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1537                        receiverDead = true;
1538                    }
1539                }
1540            }
1541
1542            long prevStatusUpdateTime = r.mLastStatusBroadcast;
1543            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1544                    (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1545
1546                r.mLastStatusBroadcast = newStatusUpdateTime;
1547                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1548                    receiverDead = true;
1549                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1550                }
1551            }
1552
1553            // track expired records
1554            if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1555                if (deadUpdateRecords == null) {
1556                    deadUpdateRecords = new ArrayList<UpdateRecord>();
1557                }
1558                deadUpdateRecords.add(r);
1559            }
1560            // track dead receivers
1561            if (receiverDead) {
1562                if (deadReceivers == null) {
1563                    deadReceivers = new ArrayList<Receiver>();
1564                }
1565                if (!deadReceivers.contains(receiver)) {
1566                    deadReceivers.add(receiver);
1567                }
1568            }
1569        }
1570
1571        // remove dead records and receivers outside the loop
1572        if (deadReceivers != null) {
1573            for (Receiver receiver : deadReceivers) {
1574                removeUpdatesLocked(receiver);
1575            }
1576        }
1577        if (deadUpdateRecords != null) {
1578            for (UpdateRecord r : deadUpdateRecords) {
1579                r.disposeLocked(true);
1580            }
1581        }
1582    }
1583
1584    private class LocationWorkerHandler extends Handler {
1585        @Override
1586        public void handleMessage(Message msg) {
1587            switch (msg.what) {
1588                case MSG_LOCATION_CHANGED:
1589                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1590                    break;
1591            }
1592        }
1593    }
1594
1595    private void handleLocationChanged(Location location, boolean passive) {
1596        String provider = location.getProvider();
1597
1598        if (!passive) {
1599            // notify passive provider of the new location
1600            mPassiveProvider.updateLocation(location);
1601        }
1602
1603        synchronized (mLock) {
1604            if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
1605                handleLocationChangedLocked(location, passive);
1606            }
1607        }
1608    }
1609
1610    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1611        @Override
1612        public void onPackageDisappeared(String packageName, int reason) {
1613            // remove all receivers associated with this package name
1614            synchronized (mLock) {
1615                ArrayList<Receiver> deadReceivers = null;
1616
1617                for (Receiver receiver : mReceivers.values()) {
1618                    if (receiver.mPackageName.equals(packageName)) {
1619                        if (deadReceivers == null) {
1620                            deadReceivers = new ArrayList<Receiver>();
1621                        }
1622                        deadReceivers.add(receiver);
1623                    }
1624                }
1625
1626                // perform removal outside of mReceivers loop
1627                if (deadReceivers != null) {
1628                    for (Receiver receiver : deadReceivers) {
1629                        removeUpdatesLocked(receiver);
1630                    }
1631                }
1632            }
1633        }
1634    };
1635
1636    // Wake locks
1637
1638    private void incrementPendingBroadcasts() {
1639        synchronized (mWakeLock) {
1640            if (mPendingBroadcasts++ == 0) {
1641                try {
1642                    mWakeLock.acquire();
1643                    log("Acquired wakelock");
1644                } catch (Exception e) {
1645                    // This is to catch a runtime exception thrown when we try to release an
1646                    // already released lock.
1647                    Slog.e(TAG, "exception in acquireWakeLock()", e);
1648                }
1649            }
1650        }
1651    }
1652
1653    private void decrementPendingBroadcasts() {
1654        synchronized (mWakeLock) {
1655            if (--mPendingBroadcasts == 0) {
1656                try {
1657                    // Release wake lock
1658                    if (mWakeLock.isHeld()) {
1659                        mWakeLock.release();
1660                        log("Released wakelock");
1661                    } else {
1662                        log("Can't release wakelock again!");
1663                    }
1664                } catch (Exception e) {
1665                    // This is to catch a runtime exception thrown when we try to release an
1666                    // already released lock.
1667                    Slog.e(TAG, "exception in releaseWakeLock()", e);
1668                }
1669            }
1670        }
1671    }
1672
1673    // Geocoder
1674
1675    @Override
1676    public boolean geocoderIsPresent() {
1677        return mGeocodeProvider != null;
1678    }
1679
1680    @Override
1681    public String getFromLocation(double latitude, double longitude, int maxResults,
1682            GeocoderParams params, List<Address> addrs) {
1683        if (mGeocodeProvider != null) {
1684            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1685                    params, addrs);
1686        }
1687        return null;
1688    }
1689
1690
1691    @Override
1692    public String getFromLocationName(String locationName,
1693            double lowerLeftLatitude, double lowerLeftLongitude,
1694            double upperRightLatitude, double upperRightLongitude, int maxResults,
1695            GeocoderParams params, List<Address> addrs) {
1696
1697        if (mGeocodeProvider != null) {
1698            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1699                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1700                    maxResults, params, addrs);
1701        }
1702        return null;
1703    }
1704
1705    // Mock Providers
1706
1707    private void checkMockPermissionsSafe() {
1708        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1709                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1710        if (!allowMocks) {
1711            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1712        }
1713
1714        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1715            PackageManager.PERMISSION_GRANTED) {
1716            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1717        }
1718    }
1719
1720    @Override
1721    public void addTestProvider(String name, ProviderProperties properties) {
1722        checkMockPermissionsSafe();
1723
1724        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1725            throw new IllegalArgumentException("Cannot mock the passive location provider");
1726        }
1727
1728        long identity = Binder.clearCallingIdentity();
1729        synchronized (mLock) {
1730            MockProvider provider = new MockProvider(name, this, properties);
1731            // remove the real provider if we are replacing GPS or network provider
1732            if (LocationManager.GPS_PROVIDER.equals(name)
1733                    || LocationManager.NETWORK_PROVIDER.equals(name)
1734                    || LocationManager.FUSED_PROVIDER.equals(name)) {
1735                LocationProviderInterface p = mProvidersByName.get(name);
1736                if (p != null) {
1737                    removeProviderLocked(p);
1738                }
1739            }
1740            if (mProvidersByName.get(name) != null) {
1741                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1742            }
1743            addProviderLocked(provider);
1744            mMockProviders.put(name, provider);
1745            mLastLocation.put(name, null);
1746            updateProvidersLocked();
1747        }
1748        Binder.restoreCallingIdentity(identity);
1749    }
1750
1751    @Override
1752    public void removeTestProvider(String provider) {
1753        checkMockPermissionsSafe();
1754        synchronized (mLock) {
1755            MockProvider mockProvider = mMockProviders.get(provider);
1756            if (mockProvider == null) {
1757                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1758            }
1759            long identity = Binder.clearCallingIdentity();
1760            removeProviderLocked(mProvidersByName.get(provider));
1761            mMockProviders.remove(mockProvider);
1762
1763            // reinstate real provider if available
1764            LocationProviderInterface realProvider = mRealProviders.get(provider);
1765            if (realProvider != null) {
1766                addProviderLocked(realProvider);
1767            }
1768            mLastLocation.put(provider, null);
1769            updateProvidersLocked();
1770            Binder.restoreCallingIdentity(identity);
1771        }
1772    }
1773
1774    @Override
1775    public void setTestProviderLocation(String provider, Location loc) {
1776        checkMockPermissionsSafe();
1777        synchronized (mLock) {
1778            MockProvider mockProvider = mMockProviders.get(provider);
1779            if (mockProvider == null) {
1780                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1781            }
1782            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1783            long identity = Binder.clearCallingIdentity();
1784            mockProvider.setLocation(loc);
1785            Binder.restoreCallingIdentity(identity);
1786        }
1787    }
1788
1789    @Override
1790    public void clearTestProviderLocation(String provider) {
1791        checkMockPermissionsSafe();
1792        synchronized (mLock) {
1793            MockProvider mockProvider = mMockProviders.get(provider);
1794            if (mockProvider == null) {
1795                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1796            }
1797            mockProvider.clearLocation();
1798        }
1799    }
1800
1801    @Override
1802    public void setTestProviderEnabled(String provider, boolean enabled) {
1803        checkMockPermissionsSafe();
1804        synchronized (mLock) {
1805            MockProvider mockProvider = mMockProviders.get(provider);
1806            if (mockProvider == null) {
1807                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1808            }
1809            long identity = Binder.clearCallingIdentity();
1810            if (enabled) {
1811                mockProvider.enable();
1812                mEnabledProviders.add(provider);
1813                mDisabledProviders.remove(provider);
1814            } else {
1815                mockProvider.disable();
1816                mEnabledProviders.remove(provider);
1817                mDisabledProviders.add(provider);
1818            }
1819            updateProvidersLocked();
1820            Binder.restoreCallingIdentity(identity);
1821        }
1822    }
1823
1824    @Override
1825    public void clearTestProviderEnabled(String provider) {
1826        checkMockPermissionsSafe();
1827        synchronized (mLock) {
1828            MockProvider mockProvider = mMockProviders.get(provider);
1829            if (mockProvider == null) {
1830                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1831            }
1832            long identity = Binder.clearCallingIdentity();
1833            mEnabledProviders.remove(provider);
1834            mDisabledProviders.remove(provider);
1835            updateProvidersLocked();
1836            Binder.restoreCallingIdentity(identity);
1837        }
1838    }
1839
1840    @Override
1841    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1842        checkMockPermissionsSafe();
1843        synchronized (mLock) {
1844            MockProvider mockProvider = mMockProviders.get(provider);
1845            if (mockProvider == null) {
1846                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1847            }
1848            mockProvider.setStatus(status, extras, updateTime);
1849        }
1850    }
1851
1852    @Override
1853    public void clearTestProviderStatus(String provider) {
1854        checkMockPermissionsSafe();
1855        synchronized (mLock) {
1856            MockProvider mockProvider = mMockProviders.get(provider);
1857            if (mockProvider == null) {
1858                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1859            }
1860            mockProvider.clearStatus();
1861        }
1862    }
1863
1864    private void log(String log) {
1865        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1866            Slog.d(TAG, log);
1867        }
1868    }
1869
1870    @Override
1871    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1872        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1873                != PackageManager.PERMISSION_GRANTED) {
1874            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
1875                    + Binder.getCallingPid()
1876                    + ", uid=" + Binder.getCallingUid());
1877            return;
1878        }
1879
1880        synchronized (mLock) {
1881            pw.println("Current Location Manager state:");
1882            pw.println("  Location Listeners:");
1883            for (Receiver receiver : mReceivers.values()) {
1884                pw.println("    " + receiver);
1885            }
1886            pw.println("  Records by Provider:");
1887            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1888                pw.println("    " + entry.getKey() + ":");
1889                for (UpdateRecord record : entry.getValue()) {
1890                    pw.println("      " + record);
1891                }
1892            }
1893            pw.println("  Last Known Locations:");
1894            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1895                String provider = entry.getKey();
1896                Location location = entry.getValue();
1897                pw.println("    " + provider + ": " + location);
1898            }
1899
1900            mGeofenceManager.dump(pw);
1901
1902            if (mEnabledProviders.size() > 0) {
1903                pw.println("  Enabled Providers:");
1904                for (String i : mEnabledProviders) {
1905                    pw.println("    " + i);
1906                }
1907
1908            }
1909            if (mDisabledProviders.size() > 0) {
1910                pw.println("  Disabled Providers:");
1911                for (String i : mDisabledProviders) {
1912                    pw.println("    " + i);
1913                }
1914            }
1915            pw.append("  ");
1916            mBlacklist.dump(pw);
1917            if (mMockProviders.size() > 0) {
1918                pw.println("  Mock Providers:");
1919                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
1920                    i.getValue().dump(pw, "      ");
1921                }
1922            }
1923
1924            pw.append("  fudger: ");
1925            mLocationFudger.dump(fd, pw,  args);
1926
1927            if (args.length > 0 && "short".equals(args[0])) {
1928                return;
1929            }
1930            for (LocationProviderInterface provider: mProviders) {
1931                pw.print(provider.getName() + " Internal State");
1932                if (provider instanceof LocationProviderProxy) {
1933                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
1934                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
1935                }
1936                pw.println(":");
1937                provider.dump(fd, pw, args);
1938            }
1939        }
1940    }
1941}
1942