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