• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.server;
18 
19 import android.app.Activity;
20 import android.app.PendingIntent;
21 import android.content.BroadcastReceiver;
22 import android.content.ComponentName;
23 import android.content.ContentQueryMap;
24 import android.content.ContentResolver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.ServiceConnection;
29 import android.content.pm.PackageInfo;
30 import android.content.pm.PackageManager;
31 import android.content.pm.ResolveInfo;
32 import android.content.pm.PackageManager.NameNotFoundException;
33 import android.content.pm.Signature;
34 import android.content.res.Resources;
35 import android.database.Cursor;
36 import android.location.Address;
37 import android.location.Criteria;
38 import android.location.GeocoderParams;
39 import android.location.IGpsStatusListener;
40 import android.location.IGpsStatusProvider;
41 import android.location.ILocationListener;
42 import android.location.ILocationManager;
43 import android.location.INetInitiatedListener;
44 import android.location.Location;
45 import android.location.LocationManager;
46 import android.location.LocationProvider;
47 import android.net.ConnectivityManager;
48 import android.net.NetworkInfo;
49 import android.net.Uri;
50 import android.os.Binder;
51 import android.os.Bundle;
52 import android.os.Handler;
53 import android.os.IBinder;
54 import android.os.Looper;
55 import android.os.Message;
56 import android.os.PowerManager;
57 import android.os.Process;
58 import android.os.RemoteException;
59 import android.os.WorkSource;
60 import android.provider.Settings;
61 import android.util.Log;
62 import android.util.Slog;
63 import android.util.PrintWriterPrinter;
64 
65 import com.android.internal.content.PackageMonitor;
66 import com.android.internal.location.GpsNetInitiatedHandler;
67 
68 import com.android.server.location.GeocoderProxy;
69 import com.android.server.location.GpsLocationProvider;
70 import com.android.server.location.LocationProviderInterface;
71 import com.android.server.location.LocationProviderProxy;
72 import com.android.server.location.MockProvider;
73 import com.android.server.location.PassiveProvider;
74 
75 import java.io.FileDescriptor;
76 import java.io.PrintWriter;
77 import java.util.ArrayList;
78 import java.util.Collections;
79 import java.util.Comparator;
80 import java.util.HashMap;
81 import java.util.HashSet;
82 import java.util.List;
83 import java.util.Map;
84 import java.util.Observable;
85 import java.util.Observer;
86 import java.util.Set;
87 
88 /**
89  * The service class that manages LocationProviders and issues location
90  * updates and alerts.
91  *
92  * {@hide}
93  */
94 public class LocationManagerService extends ILocationManager.Stub implements Runnable {
95     private static final String TAG = "LocationManagerService";
96     private static final boolean LOCAL_LOGV = false;
97 
98     // The last time a location was written, by provider name.
99     private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();
100 
101     private static final String ACCESS_FINE_LOCATION =
102         android.Manifest.permission.ACCESS_FINE_LOCATION;
103     private static final String ACCESS_COARSE_LOCATION =
104         android.Manifest.permission.ACCESS_COARSE_LOCATION;
105     private static final String ACCESS_MOCK_LOCATION =
106         android.Manifest.permission.ACCESS_MOCK_LOCATION;
107     private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
108         android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
109     private static final String INSTALL_LOCATION_PROVIDER =
110         android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
111 
112     // Location Providers may sometimes deliver location updates
113     // slightly faster that requested - provide grace period so
114     // we don't unnecessarily filter events that are otherwise on
115     // time
116     private static final int MAX_PROVIDER_SCHEDULING_JITTER = 100;
117 
118     // Set of providers that are explicitly enabled
119     private final Set<String> mEnabledProviders = new HashSet<String>();
120 
121     // Set of providers that are explicitly disabled
122     private final Set<String> mDisabledProviders = new HashSet<String>();
123 
124     // Locations, status values, and extras for mock providers
125     private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>();
126 
127     private static boolean sProvidersLoaded = false;
128 
129     private final Context mContext;
130     private PackageManager mPackageManager;  // final after initialize()
131     private String mNetworkLocationProviderPackageName;  // only used on handler thread
132     private String mGeocodeProviderPackageName;  // only used on handler thread
133     private GeocoderProxy mGeocodeProvider;
134     private IGpsStatusProvider mGpsStatusProvider;
135     private INetInitiatedListener mNetInitiatedListener;
136     private LocationWorkerHandler mLocationHandler;
137 
138     // Cache the real providers for use in addTestProvider() and removeTestProvider()
139      LocationProviderProxy mNetworkLocationProvider;
140      LocationProviderInterface mGpsLocationProvider;
141 
142     // Handler messages
143     private static final int MESSAGE_LOCATION_CHANGED = 1;
144     private static final int MESSAGE_PACKAGE_UPDATED = 2;
145 
146     // wakelock variables
147     private final static String WAKELOCK_KEY = "LocationManagerService";
148     private PowerManager.WakeLock mWakeLock = null;
149     private int mPendingBroadcasts;
150 
151     /**
152      * List of all receivers.
153      */
154     private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
155 
156 
157     /**
158      * List of location providers.
159      */
160     private final ArrayList<LocationProviderInterface> mProviders =
161         new ArrayList<LocationProviderInterface>();
162     private final HashMap<String, LocationProviderInterface> mProvidersByName
163         = new HashMap<String, LocationProviderInterface>();
164 
165     /**
166      * Object used internally for synchronization
167      */
168     private final Object mLock = new Object();
169 
170     /**
171      * Mapping from provider name to all its UpdateRecords
172      */
173     private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
174         new HashMap<String,ArrayList<UpdateRecord>>();
175 
176     /**
177      * Temporary filled in when computing min time for a provider.  Access is
178      * protected by global lock mLock.
179      */
180     private final WorkSource mTmpWorkSource = new WorkSource();
181 
182     // Proximity listeners
183     private Receiver mProximityReceiver = null;
184     private ILocationListener mProximityListener = null;
185     private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
186         new HashMap<PendingIntent,ProximityAlert>();
187     private HashSet<ProximityAlert> mProximitiesEntered =
188         new HashSet<ProximityAlert>();
189 
190     // Last known location for each provider
191     private HashMap<String,Location> mLastKnownLocation =
192         new HashMap<String,Location>();
193 
194     private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
195 
196     // for Settings change notification
197     private ContentQueryMap mSettings;
198 
199     /**
200      * A wrapper class holding either an ILocationListener or a PendingIntent to receive
201      * location updates.
202      */
203     private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
204         final ILocationListener mListener;
205         final PendingIntent mPendingIntent;
206         final Object mKey;
207         final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
208 
209         int mPendingBroadcasts;
210         String mRequiredPermissions;
211 
Receiver(ILocationListener listener)212         Receiver(ILocationListener listener) {
213             mListener = listener;
214             mPendingIntent = null;
215             mKey = listener.asBinder();
216         }
217 
Receiver(PendingIntent intent)218         Receiver(PendingIntent intent) {
219             mPendingIntent = intent;
220             mListener = null;
221             mKey = intent;
222         }
223 
224         @Override
equals(Object otherObj)225         public boolean equals(Object otherObj) {
226             if (otherObj instanceof Receiver) {
227                 return mKey.equals(
228                         ((Receiver)otherObj).mKey);
229             }
230             return false;
231         }
232 
233         @Override
hashCode()234         public int hashCode() {
235             return mKey.hashCode();
236         }
237 
238         @Override
toString()239         public String toString() {
240             String result;
241             if (mListener != null) {
242                 result = "Receiver{"
243                         + Integer.toHexString(System.identityHashCode(this))
244                         + " Listener " + mKey + "}";
245             } else {
246                 result = "Receiver{"
247                         + Integer.toHexString(System.identityHashCode(this))
248                         + " Intent " + mKey + "}";
249             }
250             result += "mUpdateRecords: " + mUpdateRecords;
251             return result;
252         }
253 
isListener()254         public boolean isListener() {
255             return mListener != null;
256         }
257 
isPendingIntent()258         public boolean isPendingIntent() {
259             return mPendingIntent != null;
260         }
261 
getListener()262         public ILocationListener getListener() {
263             if (mListener != null) {
264                 return mListener;
265             }
266             throw new IllegalStateException("Request for non-existent listener");
267         }
268 
getPendingIntent()269         public PendingIntent getPendingIntent() {
270             if (mPendingIntent != null) {
271                 return mPendingIntent;
272             }
273             throw new IllegalStateException("Request for non-existent intent");
274         }
275 
callStatusChangedLocked(String provider, int status, Bundle extras)276         public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
277             if (mListener != null) {
278                 try {
279                     synchronized (this) {
280                         // synchronize to ensure incrementPendingBroadcastsLocked()
281                         // is called before decrementPendingBroadcasts()
282                         mListener.onStatusChanged(provider, status, extras);
283                         if (mListener != mProximityListener) {
284                             // call this after broadcasting so we do not increment
285                             // if we throw an exeption.
286                             incrementPendingBroadcastsLocked();
287                         }
288                     }
289                 } catch (RemoteException e) {
290                     return false;
291                 }
292             } else {
293                 Intent statusChanged = new Intent();
294                 statusChanged.putExtras(extras);
295                 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
296                 try {
297                     synchronized (this) {
298                         // synchronize to ensure incrementPendingBroadcastsLocked()
299                         // is called before decrementPendingBroadcasts()
300                         mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
301                                 mRequiredPermissions);
302                         // call this after broadcasting so we do not increment
303                         // if we throw an exeption.
304                         incrementPendingBroadcastsLocked();
305                     }
306                 } catch (PendingIntent.CanceledException e) {
307                     return false;
308                 }
309             }
310             return true;
311         }
312 
callLocationChangedLocked(Location location)313         public boolean callLocationChangedLocked(Location location) {
314             if (mListener != null) {
315                 try {
316                     synchronized (this) {
317                         // synchronize to ensure incrementPendingBroadcastsLocked()
318                         // is called before decrementPendingBroadcasts()
319                         mListener.onLocationChanged(location);
320                         if (mListener != mProximityListener) {
321                             // call this after broadcasting so we do not increment
322                             // if we throw an exeption.
323                             incrementPendingBroadcastsLocked();
324                         }
325                     }
326                 } catch (RemoteException e) {
327                     return false;
328                 }
329             } else {
330                 Intent locationChanged = new Intent();
331                 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
332                 try {
333                     synchronized (this) {
334                         // synchronize to ensure incrementPendingBroadcastsLocked()
335                         // is called before decrementPendingBroadcasts()
336                         mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
337                                 mRequiredPermissions);
338                         // call this after broadcasting so we do not increment
339                         // if we throw an exeption.
340                         incrementPendingBroadcastsLocked();
341                     }
342                 } catch (PendingIntent.CanceledException e) {
343                     return false;
344                 }
345             }
346             return true;
347         }
348 
callProviderEnabledLocked(String provider, boolean enabled)349         public boolean callProviderEnabledLocked(String provider, boolean enabled) {
350             if (mListener != null) {
351                 try {
352                     synchronized (this) {
353                         // synchronize to ensure incrementPendingBroadcastsLocked()
354                         // is called before decrementPendingBroadcasts()
355                         if (enabled) {
356                             mListener.onProviderEnabled(provider);
357                         } else {
358                             mListener.onProviderDisabled(provider);
359                         }
360                         if (mListener != mProximityListener) {
361                             // call this after broadcasting so we do not increment
362                             // if we throw an exeption.
363                             incrementPendingBroadcastsLocked();
364                         }
365                     }
366                 } catch (RemoteException e) {
367                     return false;
368                 }
369             } else {
370                 Intent providerIntent = new Intent();
371                 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
372                 try {
373                     synchronized (this) {
374                         // synchronize to ensure incrementPendingBroadcastsLocked()
375                         // is called before decrementPendingBroadcasts()
376                         mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
377                                 mRequiredPermissions);
378                         // call this after broadcasting so we do not increment
379                         // if we throw an exeption.
380                         incrementPendingBroadcastsLocked();
381                     }
382                 } catch (PendingIntent.CanceledException e) {
383                     return false;
384                 }
385             }
386             return true;
387         }
388 
389         @Override
binderDied()390         public void binderDied() {
391             if (LOCAL_LOGV) {
392                 Slog.v(TAG, "Location listener died");
393             }
394             synchronized (mLock) {
395                 removeUpdatesLocked(this);
396             }
397             synchronized (this) {
398                 if (mPendingBroadcasts > 0) {
399                     LocationManagerService.this.decrementPendingBroadcasts();
400                     mPendingBroadcasts = 0;
401                 }
402             }
403         }
404 
onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, String resultData, Bundle resultExtras)405         public void onSendFinished(PendingIntent pendingIntent, Intent intent,
406                 int resultCode, String resultData, Bundle resultExtras) {
407             synchronized (this) {
408                 decrementPendingBroadcastsLocked();
409             }
410         }
411 
412         // this must be called while synchronized by caller in a synchronized block
413         // containing the sending of the broadcaset
incrementPendingBroadcastsLocked()414         private void incrementPendingBroadcastsLocked() {
415             if (mPendingBroadcasts++ == 0) {
416                 LocationManagerService.this.incrementPendingBroadcasts();
417             }
418         }
419 
decrementPendingBroadcastsLocked()420         private void decrementPendingBroadcastsLocked() {
421             if (--mPendingBroadcasts == 0) {
422                 LocationManagerService.this.decrementPendingBroadcasts();
423             }
424         }
425     }
426 
locationCallbackFinished(ILocationListener listener)427     public void locationCallbackFinished(ILocationListener listener) {
428         //Do not use getReceiver here as that will add the ILocationListener to
429         //the receiver list if it is not found.  If it is not found then the
430         //LocationListener was removed when it had a pending broadcast and should
431         //not be added back.
432         IBinder binder = listener.asBinder();
433         Receiver receiver = mReceivers.get(binder);
434         if (receiver != null) {
435             synchronized (receiver) {
436                 // so wakelock calls will succeed
437                 long identity = Binder.clearCallingIdentity();
438                 receiver.decrementPendingBroadcastsLocked();
439                 Binder.restoreCallingIdentity(identity);
440            }
441         }
442     }
443 
444     private final class SettingsObserver implements Observer {
update(Observable o, Object arg)445         public void update(Observable o, Object arg) {
446             synchronized (mLock) {
447                 updateProvidersLocked();
448             }
449         }
450     }
451 
addProvider(LocationProviderInterface provider)452     private void addProvider(LocationProviderInterface provider) {
453         mProviders.add(provider);
454         mProvidersByName.put(provider.getName(), provider);
455     }
456 
removeProvider(LocationProviderInterface provider)457     private void removeProvider(LocationProviderInterface provider) {
458         mProviders.remove(provider);
459         mProvidersByName.remove(provider.getName());
460     }
461 
loadProviders()462     private void loadProviders() {
463         synchronized (mLock) {
464             if (sProvidersLoaded) {
465                 return;
466             }
467 
468             // Load providers
469             loadProvidersLocked();
470             sProvidersLoaded = true;
471         }
472     }
473 
loadProvidersLocked()474     private void loadProvidersLocked() {
475         try {
476             _loadProvidersLocked();
477         } catch (Exception e) {
478             Slog.e(TAG, "Exception loading providers:", e);
479         }
480     }
481 
_loadProvidersLocked()482     private void _loadProvidersLocked() {
483         // Attempt to load "real" providers first
484         if (GpsLocationProvider.isSupported()) {
485             // Create a gps location provider
486             GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
487             mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
488             mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
489             addProvider(gpsProvider);
490             mGpsLocationProvider = gpsProvider;
491         }
492 
493         // create a passive location provider, which is always enabled
494         PassiveProvider passiveProvider = new PassiveProvider(this);
495         addProvider(passiveProvider);
496         mEnabledProviders.add(passiveProvider.getName());
497 
498         // initialize external network location and geocoder services.
499         // The initial value of mNetworkLocationProviderPackageName and
500         // mGeocodeProviderPackageName is just used to determine what
501         // signatures future mNetworkLocationProviderPackageName and
502         // mGeocodeProviderPackageName packages must have. So alternate
503         // providers can be installed under a different package name
504         // so long as they have the same signature as the original
505         // provider packages.
506         if (mNetworkLocationProviderPackageName != null) {
507             String packageName = findBestPackage(LocationProviderProxy.SERVICE_ACTION,
508                     mNetworkLocationProviderPackageName);
509             if (packageName != null) {
510                 mNetworkLocationProvider = new LocationProviderProxy(mContext,
511                         LocationManager.NETWORK_PROVIDER,
512                         packageName, mLocationHandler);
513                 mNetworkLocationProviderPackageName = packageName;
514                 addProvider(mNetworkLocationProvider);
515             }
516         }
517         if (mGeocodeProviderPackageName != null) {
518             String packageName = findBestPackage(GeocoderProxy.SERVICE_ACTION,
519                     mGeocodeProviderPackageName);
520             if (packageName != null) {
521                 mGeocodeProvider = new GeocoderProxy(mContext, packageName);
522                 mGeocodeProviderPackageName = packageName;
523             }
524         }
525 
526         updateProvidersLocked();
527     }
528 
529     /**
530      * Pick the best (network location provider or geocode provider) package.
531      * The best package:
532      * - implements serviceIntentName
533      * - has signatures that match that of sigPackageName
534      * - has the highest version value in a meta-data field in the service component
535      */
findBestPackage(String serviceIntentName, String sigPackageName)536     String findBestPackage(String serviceIntentName, String sigPackageName) {
537         Intent intent = new Intent(serviceIntentName);
538         List<ResolveInfo> infos = mPackageManager.queryIntentServices(intent,
539                 PackageManager.GET_META_DATA);
540         if (infos == null) return null;
541 
542         int bestVersion = Integer.MIN_VALUE;
543         String bestPackage = null;
544         for (ResolveInfo info : infos) {
545             String packageName = info.serviceInfo.packageName;
546             // check signature
547             if (mPackageManager.checkSignatures(packageName, sigPackageName) !=
548                     PackageManager.SIGNATURE_MATCH) {
549                 Slog.w(TAG, packageName + " implements " + serviceIntentName +
550                        " but its signatures don't match those in " + sigPackageName +
551                        ", ignoring");
552                 continue;
553             }
554             // read version
555             int version = 0;
556             if (info.serviceInfo.metaData != null) {
557                 version = info.serviceInfo.metaData.getInt("version", 0);
558             }
559             if (LOCAL_LOGV) Slog.v(TAG, packageName + " implements " + serviceIntentName +
560                     " with version " + version);
561             if (version > bestVersion) {
562                 bestVersion = version;
563                 bestPackage = packageName;
564             }
565         }
566 
567         return bestPackage;
568     }
569 
570     /**
571      * @param context the context that the LocationManagerService runs in
572      */
LocationManagerService(Context context)573     public LocationManagerService(Context context) {
574         super();
575         mContext = context;
576         Resources resources = context.getResources();
577 
578         mNetworkLocationProviderPackageName = resources.getString(
579                 com.android.internal.R.string.config_networkLocationProviderPackageName);
580         mGeocodeProviderPackageName = resources.getString(
581                 com.android.internal.R.string.config_geocodeProviderPackageName);
582 
583         mPackageMonitor.register(context, null, true);
584 
585         if (LOCAL_LOGV) {
586             Slog.v(TAG, "Constructed LocationManager Service");
587         }
588     }
589 
systemReady()590     void systemReady() {
591         // we defer starting up the service until the system is ready
592         Thread thread = new Thread(null, this, "LocationManagerService");
593         thread.start();
594     }
595 
initialize()596     private void initialize() {
597         // Create a wake lock, needs to be done before calling loadProviders() below
598         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
599         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
600         mPackageManager = mContext.getPackageManager();
601 
602         // Load providers
603         loadProviders();
604 
605         // Register for Network (Wifi or Mobile) updates
606         IntentFilter intentFilter = new IntentFilter();
607         intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
608         // Register for Package Manager updates
609         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
610         intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
611         intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
612         mContext.registerReceiver(mBroadcastReceiver, intentFilter);
613         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
614         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
615 
616         // listen for settings changes
617         ContentResolver resolver = mContext.getContentResolver();
618         Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
619                 "(" + Settings.System.NAME + "=?)",
620                 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
621                 null);
622         mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
623         SettingsObserver settingsObserver = new SettingsObserver();
624         mSettings.addObserver(settingsObserver);
625     }
626 
run()627     public void run()
628     {
629         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
630         Looper.prepare();
631         mLocationHandler = new LocationWorkerHandler();
632         initialize();
633         Looper.loop();
634     }
635 
isAllowedBySettingsLocked(String provider)636     private boolean isAllowedBySettingsLocked(String provider) {
637         if (mEnabledProviders.contains(provider)) {
638             return true;
639         }
640         if (mDisabledProviders.contains(provider)) {
641             return false;
642         }
643         // Use system settings
644         ContentResolver resolver = mContext.getContentResolver();
645 
646         return Settings.Secure.isLocationProviderEnabled(resolver, provider);
647     }
648 
checkPermissionsSafe(String provider, String lastPermission)649     private String checkPermissionsSafe(String provider, String lastPermission) {
650         if (LocationManager.GPS_PROVIDER.equals(provider)
651                  || LocationManager.PASSIVE_PROVIDER.equals(provider)) {
652             if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
653                     != PackageManager.PERMISSION_GRANTED) {
654                 throw new SecurityException("Provider " + provider
655                         + " requires ACCESS_FINE_LOCATION permission");
656             }
657             return ACCESS_FINE_LOCATION;
658         }
659 
660         // Assume any other provider requires the coarse or fine permission.
661         if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
662                 == PackageManager.PERMISSION_GRANTED) {
663             return ACCESS_FINE_LOCATION.equals(lastPermission)
664                     ? lastPermission : ACCESS_COARSE_LOCATION;
665         }
666         if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
667                 == PackageManager.PERMISSION_GRANTED) {
668             return ACCESS_FINE_LOCATION;
669         }
670 
671         throw new SecurityException("Provider " + provider
672                 + " requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
673     }
674 
isAllowedProviderSafe(String provider)675     private boolean isAllowedProviderSafe(String provider) {
676         if ((LocationManager.GPS_PROVIDER.equals(provider)
677                 || LocationManager.PASSIVE_PROVIDER.equals(provider))
678             && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
679                 != PackageManager.PERMISSION_GRANTED)) {
680             return false;
681         }
682         if (LocationManager.NETWORK_PROVIDER.equals(provider)
683             && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
684                 != PackageManager.PERMISSION_GRANTED)
685             && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
686                 != PackageManager.PERMISSION_GRANTED)) {
687             return false;
688         }
689 
690         return true;
691     }
692 
getAllProviders()693     public List<String> getAllProviders() {
694         try {
695             synchronized (mLock) {
696                 return _getAllProvidersLocked();
697             }
698         } catch (SecurityException se) {
699             throw se;
700         } catch (Exception e) {
701             Slog.e(TAG, "getAllProviders got exception:", e);
702             return null;
703         }
704     }
705 
_getAllProvidersLocked()706     private List<String> _getAllProvidersLocked() {
707         if (LOCAL_LOGV) {
708             Slog.v(TAG, "getAllProviders");
709         }
710         ArrayList<String> out = new ArrayList<String>(mProviders.size());
711         for (int i = mProviders.size() - 1; i >= 0; i--) {
712             LocationProviderInterface p = mProviders.get(i);
713             out.add(p.getName());
714         }
715         return out;
716     }
717 
getProviders(Criteria criteria, boolean enabledOnly)718     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
719         try {
720             synchronized (mLock) {
721                 return _getProvidersLocked(criteria, enabledOnly);
722             }
723         } catch (SecurityException se) {
724             throw se;
725         } catch (Exception e) {
726             Slog.e(TAG, "getProviders got exception:", e);
727             return null;
728         }
729     }
730 
_getProvidersLocked(Criteria criteria, boolean enabledOnly)731     private List<String> _getProvidersLocked(Criteria criteria, boolean enabledOnly) {
732         if (LOCAL_LOGV) {
733             Slog.v(TAG, "getProviders");
734         }
735         ArrayList<String> out = new ArrayList<String>(mProviders.size());
736         for (int i = mProviders.size() - 1; i >= 0; i--) {
737             LocationProviderInterface p = mProviders.get(i);
738             String name = p.getName();
739             if (isAllowedProviderSafe(name)) {
740                 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
741                     continue;
742                 }
743                 if (criteria != null && !p.meetsCriteria(criteria)) {
744                     continue;
745                 }
746                 out.add(name);
747             }
748         }
749         return out;
750     }
751 
752     /**
753      * Returns the next looser power requirement, in the sequence:
754      *
755      * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT
756      */
nextPower(int power)757     private int nextPower(int power) {
758         switch (power) {
759         case Criteria.POWER_LOW:
760             return Criteria.POWER_MEDIUM;
761         case Criteria.POWER_MEDIUM:
762             return Criteria.POWER_HIGH;
763         case Criteria.POWER_HIGH:
764             return Criteria.NO_REQUIREMENT;
765         case Criteria.NO_REQUIREMENT:
766         default:
767             return Criteria.NO_REQUIREMENT;
768         }
769     }
770 
771     /**
772      * Returns the next looser accuracy requirement, in the sequence:
773      *
774      * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT
775      */
nextAccuracy(int accuracy)776     private int nextAccuracy(int accuracy) {
777         if (accuracy == Criteria.ACCURACY_FINE) {
778             return Criteria.ACCURACY_COARSE;
779         } else {
780             return Criteria.NO_REQUIREMENT;
781         }
782     }
783 
784     private class LpPowerComparator implements Comparator<LocationProviderInterface> {
compare(LocationProviderInterface l1, LocationProviderInterface l2)785         public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
786             // Smaller is better
787             return (l1.getPowerRequirement() - l2.getPowerRequirement());
788          }
789 
equals(LocationProviderInterface l1, LocationProviderInterface l2)790          public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
791              return (l1.getPowerRequirement() == l2.getPowerRequirement());
792          }
793     }
794 
795     private class LpAccuracyComparator implements Comparator<LocationProviderInterface> {
compare(LocationProviderInterface l1, LocationProviderInterface l2)796         public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
797             // Smaller is better
798             return (l1.getAccuracy() - l2.getAccuracy());
799          }
800 
equals(LocationProviderInterface l1, LocationProviderInterface l2)801          public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
802              return (l1.getAccuracy() == l2.getAccuracy());
803          }
804     }
805 
806     private class LpCapabilityComparator implements Comparator<LocationProviderInterface> {
807 
808         private static final int ALTITUDE_SCORE = 4;
809         private static final int BEARING_SCORE = 4;
810         private static final int SPEED_SCORE = 4;
811 
score(LocationProviderInterface p)812         private int score(LocationProviderInterface p) {
813             return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) +
814                 (p.supportsBearing() ? BEARING_SCORE : 0) +
815                 (p.supportsSpeed() ? SPEED_SCORE : 0);
816         }
817 
compare(LocationProviderInterface l1, LocationProviderInterface l2)818         public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
819             return (score(l2) - score(l1)); // Bigger is better
820          }
821 
equals(LocationProviderInterface l1, LocationProviderInterface l2)822          public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
823              return (score(l1) == score(l2));
824          }
825     }
826 
best(List<String> providerNames)827     private LocationProviderInterface best(List<String> providerNames) {
828         ArrayList<LocationProviderInterface> providers;
829         synchronized (mLock) {
830             providers = new ArrayList<LocationProviderInterface>(providerNames.size());
831             for (String name : providerNames) {
832                 providers.add(mProvidersByName.get(name));
833             }
834         }
835 
836         if (providers.size() < 2) {
837             return providers.get(0);
838         }
839 
840         // First, sort by power requirement
841         Collections.sort(providers, new LpPowerComparator());
842         int power = providers.get(0).getPowerRequirement();
843         if (power < providers.get(1).getPowerRequirement()) {
844             return providers.get(0);
845         }
846 
847         int idx, size;
848 
849         ArrayList<LocationProviderInterface> tmp = new ArrayList<LocationProviderInterface>();
850         idx = 0;
851         size = providers.size();
852         while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) {
853             tmp.add(providers.get(idx));
854             idx++;
855         }
856 
857         // Next, sort by accuracy
858         Collections.sort(tmp, new LpAccuracyComparator());
859         int acc = tmp.get(0).getAccuracy();
860         if (acc < tmp.get(1).getAccuracy()) {
861             return tmp.get(0);
862         }
863 
864         ArrayList<LocationProviderInterface> tmp2 = new ArrayList<LocationProviderInterface>();
865         idx = 0;
866         size = tmp.size();
867         while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) {
868             tmp2.add(tmp.get(idx));
869             idx++;
870         }
871 
872         // Finally, sort by capability "score"
873         Collections.sort(tmp2, new LpCapabilityComparator());
874         return tmp2.get(0);
875     }
876 
877     /**
878      * Returns the name of the provider that best meets the given criteria. Only providers
879      * that are permitted to be accessed by the calling activity will be
880      * returned.  If several providers meet the criteria, the one with the best
881      * accuracy is returned.  If no provider meets the criteria,
882      * the criteria are loosened in the following sequence:
883      *
884      * <ul>
885      * <li> power requirement
886      * <li> accuracy
887      * <li> bearing
888      * <li> speed
889      * <li> altitude
890      * </ul>
891      *
892      * <p> Note that the requirement on monetary cost is not removed
893      * in this process.
894      *
895      * @param criteria the criteria that need to be matched
896      * @param enabledOnly if true then only a provider that is currently enabled is returned
897      * @return name of the provider that best matches the requirements
898      */
getBestProvider(Criteria criteria, boolean enabledOnly)899     public String getBestProvider(Criteria criteria, boolean enabledOnly) {
900         List<String> goodProviders = getProviders(criteria, enabledOnly);
901         if (!goodProviders.isEmpty()) {
902             return best(goodProviders).getName();
903         }
904 
905         // Make a copy of the criteria that we can modify
906         criteria = new Criteria(criteria);
907 
908         // Loosen power requirement
909         int power = criteria.getPowerRequirement();
910         while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) {
911             power = nextPower(power);
912             criteria.setPowerRequirement(power);
913             goodProviders = getProviders(criteria, enabledOnly);
914         }
915         if (!goodProviders.isEmpty()) {
916             return best(goodProviders).getName();
917         }
918 
919         // Loosen accuracy requirement
920         int accuracy = criteria.getAccuracy();
921         while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) {
922             accuracy = nextAccuracy(accuracy);
923             criteria.setAccuracy(accuracy);
924             goodProviders = getProviders(criteria, enabledOnly);
925         }
926         if (!goodProviders.isEmpty()) {
927             return best(goodProviders).getName();
928         }
929 
930         // Remove bearing requirement
931         criteria.setBearingRequired(false);
932         goodProviders = getProviders(criteria, enabledOnly);
933         if (!goodProviders.isEmpty()) {
934             return best(goodProviders).getName();
935         }
936 
937         // Remove speed requirement
938         criteria.setSpeedRequired(false);
939         goodProviders = getProviders(criteria, enabledOnly);
940         if (!goodProviders.isEmpty()) {
941             return best(goodProviders).getName();
942         }
943 
944         // Remove altitude requirement
945         criteria.setAltitudeRequired(false);
946         goodProviders = getProviders(criteria, enabledOnly);
947         if (!goodProviders.isEmpty()) {
948             return best(goodProviders).getName();
949         }
950 
951         return null;
952     }
953 
providerMeetsCriteria(String provider, Criteria criteria)954     public boolean providerMeetsCriteria(String provider, Criteria criteria) {
955         LocationProviderInterface p = mProvidersByName.get(provider);
956         if (p == null) {
957             throw new IllegalArgumentException("provider=" + provider);
958         }
959         return p.meetsCriteria(criteria);
960     }
961 
updateProvidersLocked()962     private void updateProvidersLocked() {
963         boolean changesMade = false;
964         for (int i = mProviders.size() - 1; i >= 0; i--) {
965             LocationProviderInterface p = mProviders.get(i);
966             boolean isEnabled = p.isEnabled();
967             String name = p.getName();
968             boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
969             if (isEnabled && !shouldBeEnabled) {
970                 updateProviderListenersLocked(name, false);
971                 changesMade = true;
972             } else if (!isEnabled && shouldBeEnabled) {
973                 updateProviderListenersLocked(name, true);
974                 changesMade = true;
975             }
976         }
977         if (changesMade) {
978             mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
979         }
980     }
981 
updateProviderListenersLocked(String provider, boolean enabled)982     private void updateProviderListenersLocked(String provider, boolean enabled) {
983         int listeners = 0;
984 
985         LocationProviderInterface p = mProvidersByName.get(provider);
986         if (p == null) {
987             return;
988         }
989 
990         ArrayList<Receiver> deadReceivers = null;
991 
992         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
993         if (records != null) {
994             final int N = records.size();
995             for (int i=0; i<N; i++) {
996                 UpdateRecord record = records.get(i);
997                 // Sends a notification message to the receiver
998                 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
999                     if (deadReceivers == null) {
1000                         deadReceivers = new ArrayList<Receiver>();
1001                     }
1002                     deadReceivers.add(record.mReceiver);
1003                 }
1004                 listeners++;
1005             }
1006         }
1007 
1008         if (deadReceivers != null) {
1009             for (int i=deadReceivers.size()-1; i>=0; i--) {
1010                 removeUpdatesLocked(deadReceivers.get(i));
1011             }
1012         }
1013 
1014         if (enabled) {
1015             p.enable();
1016             if (listeners > 0) {
1017                 p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);
1018                 p.enableLocationTracking(true);
1019             }
1020         } else {
1021             p.enableLocationTracking(false);
1022             p.disable();
1023         }
1024     }
1025 
getMinTimeLocked(String provider)1026     private long getMinTimeLocked(String provider) {
1027         long minTime = Long.MAX_VALUE;
1028         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1029         mTmpWorkSource.clear();
1030         if (records != null) {
1031             for (int i=records.size()-1; i>=0; i--) {
1032                 UpdateRecord ur = records.get(i);
1033                 long curTime = ur.mMinTime;
1034                 if (curTime < minTime) {
1035                     minTime = curTime;
1036                 }
1037             }
1038             long inclTime = (minTime*3)/2;
1039             for (int i=records.size()-1; i>=0; i--) {
1040                 UpdateRecord ur = records.get(i);
1041                 if (ur.mMinTime <= inclTime) {
1042                     mTmpWorkSource.add(ur.mUid);
1043                 }
1044             }
1045         }
1046         return minTime;
1047     }
1048 
1049     private class UpdateRecord {
1050         final String mProvider;
1051         final Receiver mReceiver;
1052         final long mMinTime;
1053         final float mMinDistance;
1054         final boolean mSingleShot;
1055         final int mUid;
1056         Location mLastFixBroadcast;
1057         long mLastStatusBroadcast;
1058 
1059         /**
1060          * Note: must be constructed with lock held.
1061          */
UpdateRecord(String provider, long minTime, float minDistance, boolean singleShot, Receiver receiver, int uid)1062         UpdateRecord(String provider, long minTime, float minDistance, boolean singleShot,
1063             Receiver receiver, int uid) {
1064             mProvider = provider;
1065             mReceiver = receiver;
1066             mMinTime = minTime;
1067             mMinDistance = minDistance;
1068             mSingleShot = singleShot;
1069             mUid = uid;
1070 
1071             ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1072             if (records == null) {
1073                 records = new ArrayList<UpdateRecord>();
1074                 mRecordsByProvider.put(provider, records);
1075             }
1076             if (!records.contains(this)) {
1077                 records.add(this);
1078             }
1079         }
1080 
1081         /**
1082          * Method to be called when a record will no longer be used.  Calling this multiple times
1083          * must have the same effect as calling it once.
1084          */
disposeLocked()1085         void disposeLocked() {
1086             ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
1087             if (records != null) {
1088                 records.remove(this);
1089             }
1090         }
1091 
1092         @Override
toString()1093         public String toString() {
1094             return "UpdateRecord{"
1095                     + Integer.toHexString(System.identityHashCode(this))
1096                     + " mProvider: " + mProvider + " mUid: " + mUid + "}";
1097         }
1098 
dump(PrintWriter pw, String prefix)1099         void dump(PrintWriter pw, String prefix) {
1100             pw.println(prefix + this);
1101             pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
1102             pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
1103             pw.println(prefix + "mSingleShot=" + mSingleShot);
1104             pw.println(prefix + "mUid=" + mUid);
1105             pw.println(prefix + "mLastFixBroadcast:");
1106             if (mLastFixBroadcast != null) {
1107                 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + "  ");
1108             }
1109             pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
1110         }
1111     }
1112 
getReceiver(ILocationListener listener)1113     private Receiver getReceiver(ILocationListener listener) {
1114         IBinder binder = listener.asBinder();
1115         Receiver receiver = mReceivers.get(binder);
1116         if (receiver == null) {
1117             receiver = new Receiver(listener);
1118             mReceivers.put(binder, receiver);
1119 
1120             try {
1121                 if (receiver.isListener()) {
1122                     receiver.getListener().asBinder().linkToDeath(receiver, 0);
1123                 }
1124             } catch (RemoteException e) {
1125                 Slog.e(TAG, "linkToDeath failed:", e);
1126                 return null;
1127             }
1128         }
1129         return receiver;
1130     }
1131 
getReceiver(PendingIntent intent)1132     private Receiver getReceiver(PendingIntent intent) {
1133         Receiver receiver = mReceivers.get(intent);
1134         if (receiver == null) {
1135             receiver = new Receiver(intent);
1136             mReceivers.put(intent, receiver);
1137         }
1138         return receiver;
1139     }
1140 
providerHasListener(String provider, int uid, Receiver excludedReceiver)1141     private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) {
1142         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1143         if (records != null) {
1144             for (int i = records.size() - 1; i >= 0; i--) {
1145                 UpdateRecord record = records.get(i);
1146                 if (record.mUid == uid && record.mReceiver != excludedReceiver) {
1147                     return true;
1148                 }
1149            }
1150         }
1151         for (ProximityAlert alert : mProximityAlerts.values()) {
1152             if (alert.mUid == uid) {
1153                 return true;
1154             }
1155         }
1156         return false;
1157     }
1158 
requestLocationUpdates(String provider, Criteria criteria, long minTime, float minDistance, boolean singleShot, ILocationListener listener)1159     public void requestLocationUpdates(String provider, Criteria criteria,
1160         long minTime, float minDistance, boolean singleShot, ILocationListener listener) {
1161         if (criteria != null) {
1162             // FIXME - should we consider using multiple providers simultaneously
1163             // rather than only the best one?
1164             // Should we do anything different for single shot fixes?
1165             provider = getBestProvider(criteria, true);
1166             if (provider == null) {
1167                 throw new IllegalArgumentException("no providers found for criteria");
1168             }
1169         }
1170         try {
1171             synchronized (mLock) {
1172                 requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
1173                         getReceiver(listener));
1174             }
1175         } catch (SecurityException se) {
1176             throw se;
1177         } catch (IllegalArgumentException iae) {
1178             throw iae;
1179         } catch (Exception e) {
1180             Slog.e(TAG, "requestUpdates got exception:", e);
1181         }
1182     }
1183 
validatePendingIntent(PendingIntent intent)1184     void validatePendingIntent(PendingIntent intent) {
1185         if (intent.isTargetedToPackage()) {
1186             return;
1187         }
1188         Slog.i(TAG, "Given Intent does not require a specific package: "
1189                 + intent);
1190         // XXX we should really throw a security exception, if the caller's
1191         // targetSdkVersion is high enough.
1192         //throw new SecurityException("Given Intent does not require a specific package: "
1193         //        + intent);
1194     }
1195 
requestLocationUpdatesPI(String provider, Criteria criteria, long minTime, float minDistance, boolean singleShot, PendingIntent intent)1196     public void requestLocationUpdatesPI(String provider, Criteria criteria,
1197             long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
1198         validatePendingIntent(intent);
1199         if (criteria != null) {
1200             // FIXME - should we consider using multiple providers simultaneously
1201             // rather than only the best one?
1202             // Should we do anything different for single shot fixes?
1203             provider = getBestProvider(criteria, true);
1204             if (provider == null) {
1205                 throw new IllegalArgumentException("no providers found for criteria");
1206             }
1207         }
1208         try {
1209             synchronized (mLock) {
1210                 requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
1211                         getReceiver(intent));
1212             }
1213         } catch (SecurityException se) {
1214             throw se;
1215         } catch (IllegalArgumentException iae) {
1216             throw iae;
1217         } catch (Exception e) {
1218             Slog.e(TAG, "requestUpdates got exception:", e);
1219         }
1220     }
1221 
requestLocationUpdatesLocked(String provider, long minTime, float minDistance, boolean singleShot, Receiver receiver)1222     private void requestLocationUpdatesLocked(String provider, long minTime, float minDistance,
1223             boolean singleShot, Receiver receiver) {
1224 
1225         LocationProviderInterface p = mProvidersByName.get(provider);
1226         if (p == null) {
1227             throw new IllegalArgumentException("requested provider " + provider +
1228                     " doesn't exisit");
1229         }
1230         receiver.mRequiredPermissions = checkPermissionsSafe(provider,
1231                 receiver.mRequiredPermissions);
1232 
1233         // so wakelock calls will succeed
1234         final int callingPid = Binder.getCallingPid();
1235         final int callingUid = Binder.getCallingUid();
1236         boolean newUid = !providerHasListener(provider, callingUid, null);
1237         long identity = Binder.clearCallingIdentity();
1238         try {
1239             UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, singleShot,
1240                     receiver, callingUid);
1241             UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
1242             if (oldRecord != null) {
1243                 oldRecord.disposeLocked();
1244             }
1245 
1246             if (newUid) {
1247                 p.addListener(callingUid);
1248             }
1249 
1250             boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
1251             if (isProviderEnabled) {
1252                 long minTimeForProvider = getMinTimeLocked(provider);
1253                 Slog.i(TAG, "request " + provider + " (pid " + callingPid + ") " + minTime +
1254                         " " + minTimeForProvider + (singleShot ? " (singleshot)" : ""));
1255                 p.setMinTime(minTimeForProvider, mTmpWorkSource);
1256                 // try requesting single shot if singleShot is true, and fall back to
1257                 // regular location tracking if requestSingleShotFix() is not supported
1258                 if (!singleShot || !p.requestSingleShotFix()) {
1259                     p.enableLocationTracking(true);
1260                 }
1261             } else {
1262                 // Notify the listener that updates are currently disabled
1263                 receiver.callProviderEnabledLocked(provider, false);
1264             }
1265             if (LOCAL_LOGV) {
1266                 Slog.v(TAG, "_requestLocationUpdates: provider = " + provider + " listener = " + receiver);
1267             }
1268         } finally {
1269             Binder.restoreCallingIdentity(identity);
1270         }
1271     }
1272 
removeUpdates(ILocationListener listener)1273     public void removeUpdates(ILocationListener listener) {
1274         try {
1275             synchronized (mLock) {
1276                 removeUpdatesLocked(getReceiver(listener));
1277             }
1278         } catch (SecurityException se) {
1279             throw se;
1280         } catch (IllegalArgumentException iae) {
1281             throw iae;
1282         } catch (Exception e) {
1283             Slog.e(TAG, "removeUpdates got exception:", e);
1284         }
1285     }
1286 
removeUpdatesPI(PendingIntent intent)1287     public void removeUpdatesPI(PendingIntent intent) {
1288         try {
1289             synchronized (mLock) {
1290                 removeUpdatesLocked(getReceiver(intent));
1291             }
1292         } catch (SecurityException se) {
1293             throw se;
1294         } catch (IllegalArgumentException iae) {
1295             throw iae;
1296         } catch (Exception e) {
1297             Slog.e(TAG, "removeUpdates got exception:", e);
1298         }
1299     }
1300 
removeUpdatesLocked(Receiver receiver)1301     private void removeUpdatesLocked(Receiver receiver) {
1302         if (LOCAL_LOGV) {
1303             Slog.v(TAG, "_removeUpdates: listener = " + receiver);
1304         }
1305 
1306         // so wakelock calls will succeed
1307         final int callingPid = Binder.getCallingPid();
1308         final int callingUid = Binder.getCallingUid();
1309         long identity = Binder.clearCallingIdentity();
1310         try {
1311             if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1312                 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1313                 synchronized(receiver) {
1314                     if(receiver.mPendingBroadcasts > 0) {
1315                         decrementPendingBroadcasts();
1316                         receiver.mPendingBroadcasts = 0;
1317                     }
1318                 }
1319             }
1320 
1321             // Record which providers were associated with this listener
1322             HashSet<String> providers = new HashSet<String>();
1323             HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords;
1324             if (oldRecords != null) {
1325                 // Call dispose() on the obsolete update records.
1326                 for (UpdateRecord record : oldRecords.values()) {
1327                     if (!providerHasListener(record.mProvider, callingUid, receiver)) {
1328                         LocationProviderInterface p = mProvidersByName.get(record.mProvider);
1329                         if (p != null) {
1330                             p.removeListener(callingUid);
1331                         }
1332                     }
1333                     record.disposeLocked();
1334                 }
1335                 // Accumulate providers
1336                 providers.addAll(oldRecords.keySet());
1337             }
1338 
1339             // See if the providers associated with this listener have any
1340             // other listeners; if one does, inform it of the new smallest minTime
1341             // value; if one does not, disable location tracking for it
1342             for (String provider : providers) {
1343                 // If provider is already disabled, don't need to do anything
1344                 if (!isAllowedBySettingsLocked(provider)) {
1345                     continue;
1346                 }
1347 
1348                 boolean hasOtherListener = false;
1349                 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
1350                 if (recordsForProvider != null && recordsForProvider.size() > 0) {
1351                     hasOtherListener = true;
1352                 }
1353 
1354                 LocationProviderInterface p = mProvidersByName.get(provider);
1355                 if (p != null) {
1356                     if (hasOtherListener) {
1357                         long minTime = getMinTimeLocked(provider);
1358                         Slog.i(TAG, "remove " + provider + " (pid " + callingPid +
1359                                 "), next minTime = " + minTime);
1360                         p.setMinTime(minTime, mTmpWorkSource);
1361                     } else {
1362                         Slog.i(TAG, "remove " + provider + " (pid " + callingPid +
1363                                 "), disabled");
1364                         p.enableLocationTracking(false);
1365                     }
1366                 }
1367             }
1368         } finally {
1369             Binder.restoreCallingIdentity(identity);
1370         }
1371     }
1372 
addGpsStatusListener(IGpsStatusListener listener)1373     public boolean addGpsStatusListener(IGpsStatusListener listener) {
1374         if (mGpsStatusProvider == null) {
1375             return false;
1376         }
1377         if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
1378                 PackageManager.PERMISSION_GRANTED) {
1379             throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1380         }
1381 
1382         try {
1383             mGpsStatusProvider.addGpsStatusListener(listener);
1384         } catch (RemoteException e) {
1385             Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
1386             return false;
1387         }
1388         return true;
1389     }
1390 
removeGpsStatusListener(IGpsStatusListener listener)1391     public void removeGpsStatusListener(IGpsStatusListener listener) {
1392         synchronized (mLock) {
1393             try {
1394                 mGpsStatusProvider.removeGpsStatusListener(listener);
1395             } catch (Exception e) {
1396                 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1397             }
1398         }
1399     }
1400 
sendExtraCommand(String provider, String command, Bundle extras)1401     public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1402         if (provider == null) {
1403             // throw NullPointerException to remain compatible with previous implementation
1404             throw new NullPointerException();
1405         }
1406 
1407         // first check for permission to the provider
1408         checkPermissionsSafe(provider, null);
1409         // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1410         if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1411                 != PackageManager.PERMISSION_GRANTED)) {
1412             throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1413         }
1414 
1415         synchronized (mLock) {
1416             LocationProviderInterface p = mProvidersByName.get(provider);
1417             if (p == null) {
1418                 return false;
1419             }
1420 
1421             return p.sendExtraCommand(command, extras);
1422         }
1423     }
1424 
sendNiResponse(int notifId, int userResponse)1425     public boolean sendNiResponse(int notifId, int userResponse)
1426     {
1427         if (Binder.getCallingUid() != Process.myUid()) {
1428             throw new SecurityException(
1429                     "calling sendNiResponse from outside of the system is not allowed");
1430         }
1431         try {
1432             return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1433         }
1434         catch (RemoteException e)
1435         {
1436             Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1437             return false;
1438         }
1439     }
1440 
1441     class ProximityAlert {
1442         final int  mUid;
1443         final double mLatitude;
1444         final double mLongitude;
1445         final float mRadius;
1446         final long mExpiration;
1447         final PendingIntent mIntent;
1448         final Location mLocation;
1449 
ProximityAlert(int uid, double latitude, double longitude, float radius, long expiration, PendingIntent intent)1450         public ProximityAlert(int uid, double latitude, double longitude,
1451             float radius, long expiration, PendingIntent intent) {
1452             mUid = uid;
1453             mLatitude = latitude;
1454             mLongitude = longitude;
1455             mRadius = radius;
1456             mExpiration = expiration;
1457             mIntent = intent;
1458 
1459             mLocation = new Location("");
1460             mLocation.setLatitude(latitude);
1461             mLocation.setLongitude(longitude);
1462         }
1463 
getExpiration()1464         long getExpiration() {
1465             return mExpiration;
1466         }
1467 
getIntent()1468         PendingIntent getIntent() {
1469             return mIntent;
1470         }
1471 
isInProximity(double latitude, double longitude, float accuracy)1472         boolean isInProximity(double latitude, double longitude, float accuracy) {
1473             Location loc = new Location("");
1474             loc.setLatitude(latitude);
1475             loc.setLongitude(longitude);
1476 
1477             double radius = loc.distanceTo(mLocation);
1478             return radius <= Math.max(mRadius,accuracy);
1479         }
1480 
1481         @Override
toString()1482         public String toString() {
1483             return "ProximityAlert{"
1484                     + Integer.toHexString(System.identityHashCode(this))
1485                     + " uid " + mUid + mIntent + "}";
1486         }
1487 
dump(PrintWriter pw, String prefix)1488         void dump(PrintWriter pw, String prefix) {
1489             pw.println(prefix + this);
1490             pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
1491             pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
1492             pw.println(prefix + "mIntent=" + mIntent);
1493             pw.println(prefix + "mLocation:");
1494             mLocation.dump(new PrintWriterPrinter(pw), prefix + "  ");
1495         }
1496     }
1497 
1498     // Listener for receiving locations to trigger proximity alerts
1499     class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished {
1500 
1501         boolean isGpsAvailable = false;
1502 
1503         // Note: this is called with the lock held.
onLocationChanged(Location loc)1504         public void onLocationChanged(Location loc) {
1505 
1506             // If Gps is available, then ignore updates from NetworkLocationProvider
1507             if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
1508                 isGpsAvailable = true;
1509             }
1510             if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
1511                 return;
1512             }
1513 
1514             // Process proximity alerts
1515             long now = System.currentTimeMillis();
1516             double latitude = loc.getLatitude();
1517             double longitude = loc.getLongitude();
1518             float accuracy = loc.getAccuracy();
1519             ArrayList<PendingIntent> intentsToRemove = null;
1520 
1521             for (ProximityAlert alert : mProximityAlerts.values()) {
1522                 PendingIntent intent = alert.getIntent();
1523                 long expiration = alert.getExpiration();
1524 
1525                 if ((expiration == -1) || (now <= expiration)) {
1526                     boolean entered = mProximitiesEntered.contains(alert);
1527                     boolean inProximity =
1528                         alert.isInProximity(latitude, longitude, accuracy);
1529                     if (!entered && inProximity) {
1530                         if (LOCAL_LOGV) {
1531                             Slog.v(TAG, "Entered alert");
1532                         }
1533                         mProximitiesEntered.add(alert);
1534                         Intent enteredIntent = new Intent();
1535                         enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
1536                         try {
1537                             synchronized (this) {
1538                                 // synchronize to ensure incrementPendingBroadcasts()
1539                                 // is called before decrementPendingBroadcasts()
1540                                 intent.send(mContext, 0, enteredIntent, this, mLocationHandler,
1541                                         ACCESS_FINE_LOCATION);
1542                                 // call this after broadcasting so we do not increment
1543                                 // if we throw an exeption.
1544                                 incrementPendingBroadcasts();
1545                             }
1546                         } catch (PendingIntent.CanceledException e) {
1547                             if (LOCAL_LOGV) {
1548                                 Slog.v(TAG, "Canceled proximity alert: " + alert, e);
1549                             }
1550                             if (intentsToRemove == null) {
1551                                 intentsToRemove = new ArrayList<PendingIntent>();
1552                             }
1553                             intentsToRemove.add(intent);
1554                         }
1555                     } else if (entered && !inProximity) {
1556                         if (LOCAL_LOGV) {
1557                             Slog.v(TAG, "Exited alert");
1558                         }
1559                         mProximitiesEntered.remove(alert);
1560                         Intent exitedIntent = new Intent();
1561                         exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
1562                         try {
1563                             synchronized (this) {
1564                                 // synchronize to ensure incrementPendingBroadcasts()
1565                                 // is called before decrementPendingBroadcasts()
1566                                 intent.send(mContext, 0, exitedIntent, this, mLocationHandler,
1567                                         ACCESS_FINE_LOCATION);
1568                                 // call this after broadcasting so we do not increment
1569                                 // if we throw an exeption.
1570                                 incrementPendingBroadcasts();
1571                             }
1572                         } catch (PendingIntent.CanceledException e) {
1573                             if (LOCAL_LOGV) {
1574                                 Slog.v(TAG, "Canceled proximity alert: " + alert, e);
1575                             }
1576                             if (intentsToRemove == null) {
1577                                 intentsToRemove = new ArrayList<PendingIntent>();
1578                             }
1579                             intentsToRemove.add(intent);
1580                         }
1581                     }
1582                 } else {
1583                     // Mark alert for expiration
1584                     if (LOCAL_LOGV) {
1585                         Slog.v(TAG, "Expiring proximity alert: " + alert);
1586                     }
1587                     if (intentsToRemove == null) {
1588                         intentsToRemove = new ArrayList<PendingIntent>();
1589                     }
1590                     intentsToRemove.add(alert.getIntent());
1591                 }
1592             }
1593 
1594             // Remove expired alerts
1595             if (intentsToRemove != null) {
1596                 for (PendingIntent i : intentsToRemove) {
1597                     ProximityAlert alert = mProximityAlerts.get(i);
1598                     mProximitiesEntered.remove(alert);
1599                     removeProximityAlertLocked(i);
1600                 }
1601             }
1602         }
1603 
1604         // Note: this is called with the lock held.
onProviderDisabled(String provider)1605         public void onProviderDisabled(String provider) {
1606             if (provider.equals(LocationManager.GPS_PROVIDER)) {
1607                 isGpsAvailable = false;
1608             }
1609         }
1610 
1611         // Note: this is called with the lock held.
onProviderEnabled(String provider)1612         public void onProviderEnabled(String provider) {
1613             // ignore
1614         }
1615 
1616         // Note: this is called with the lock held.
onStatusChanged(String provider, int status, Bundle extras)1617         public void onStatusChanged(String provider, int status, Bundle extras) {
1618             if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
1619                 (status != LocationProvider.AVAILABLE)) {
1620                 isGpsAvailable = false;
1621             }
1622         }
1623 
onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, String resultData, Bundle resultExtras)1624         public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1625                 int resultCode, String resultData, Bundle resultExtras) {
1626             // synchronize to ensure incrementPendingBroadcasts()
1627             // is called before decrementPendingBroadcasts()
1628             synchronized (this) {
1629                 decrementPendingBroadcasts();
1630             }
1631         }
1632     }
1633 
addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent)1634     public void addProximityAlert(double latitude, double longitude,
1635         float radius, long expiration, PendingIntent intent) {
1636         validatePendingIntent(intent);
1637         try {
1638             synchronized (mLock) {
1639                 addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
1640             }
1641         } catch (SecurityException se) {
1642             throw se;
1643         } catch (IllegalArgumentException iae) {
1644             throw iae;
1645         } catch (Exception e) {
1646             Slog.e(TAG, "addProximityAlert got exception:", e);
1647         }
1648     }
1649 
addProximityAlertLocked(double latitude, double longitude, float radius, long expiration, PendingIntent intent)1650     private void addProximityAlertLocked(double latitude, double longitude,
1651         float radius, long expiration, PendingIntent intent) {
1652         if (LOCAL_LOGV) {
1653             Slog.v(TAG, "addProximityAlert: latitude = " + latitude +
1654                     ", longitude = " + longitude +
1655                     ", expiration = " + expiration +
1656                     ", intent = " + intent);
1657         }
1658 
1659         // Require ability to access all providers for now
1660         if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1661             !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1662             throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1663         }
1664 
1665         if (expiration != -1) {
1666             expiration += System.currentTimeMillis();
1667         }
1668         ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
1669                 latitude, longitude, radius, expiration, intent);
1670         mProximityAlerts.put(intent, alert);
1671 
1672         if (mProximityReceiver == null) {
1673             mProximityListener = new ProximityListener();
1674             mProximityReceiver = new Receiver(mProximityListener);
1675 
1676             for (int i = mProviders.size() - 1; i >= 0; i--) {
1677                 LocationProviderInterface provider = mProviders.get(i);
1678                 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f,
1679                         false, mProximityReceiver);
1680             }
1681         }
1682     }
1683 
removeProximityAlert(PendingIntent intent)1684     public void removeProximityAlert(PendingIntent intent) {
1685         try {
1686             synchronized (mLock) {
1687                removeProximityAlertLocked(intent);
1688             }
1689         } catch (SecurityException se) {
1690             throw se;
1691         } catch (IllegalArgumentException iae) {
1692             throw iae;
1693         } catch (Exception e) {
1694             Slog.e(TAG, "removeProximityAlert got exception:", e);
1695         }
1696     }
1697 
removeProximityAlertLocked(PendingIntent intent)1698     private void removeProximityAlertLocked(PendingIntent intent) {
1699         if (LOCAL_LOGV) {
1700             Slog.v(TAG, "removeProximityAlert: intent = " + intent);
1701         }
1702 
1703         mProximityAlerts.remove(intent);
1704         if (mProximityAlerts.size() == 0) {
1705             if (mProximityReceiver != null) {
1706                 removeUpdatesLocked(mProximityReceiver);
1707             }
1708             mProximityReceiver = null;
1709             mProximityListener = null;
1710         }
1711      }
1712 
1713     /**
1714      * @return null if the provider does not exist
1715      * @throws SecurityException if the provider is not allowed to be
1716      * accessed by the caller
1717      */
getProviderInfo(String provider)1718     public Bundle getProviderInfo(String provider) {
1719         try {
1720             synchronized (mLock) {
1721                 return _getProviderInfoLocked(provider);
1722             }
1723         } catch (SecurityException se) {
1724             throw se;
1725         } catch (IllegalArgumentException iae) {
1726             throw iae;
1727         } catch (Exception e) {
1728             Slog.e(TAG, "_getProviderInfo got exception:", e);
1729             return null;
1730         }
1731     }
1732 
_getProviderInfoLocked(String provider)1733     private Bundle _getProviderInfoLocked(String provider) {
1734         LocationProviderInterface p = mProvidersByName.get(provider);
1735         if (p == null) {
1736             return null;
1737         }
1738 
1739         checkPermissionsSafe(provider, null);
1740 
1741         Bundle b = new Bundle();
1742         b.putBoolean("network", p.requiresNetwork());
1743         b.putBoolean("satellite", p.requiresSatellite());
1744         b.putBoolean("cell", p.requiresCell());
1745         b.putBoolean("cost", p.hasMonetaryCost());
1746         b.putBoolean("altitude", p.supportsAltitude());
1747         b.putBoolean("speed", p.supportsSpeed());
1748         b.putBoolean("bearing", p.supportsBearing());
1749         b.putInt("power", p.getPowerRequirement());
1750         b.putInt("accuracy", p.getAccuracy());
1751 
1752         return b;
1753     }
1754 
isProviderEnabled(String provider)1755     public boolean isProviderEnabled(String provider) {
1756         try {
1757             synchronized (mLock) {
1758                 return _isProviderEnabledLocked(provider);
1759             }
1760         } catch (SecurityException se) {
1761             throw se;
1762         } catch (Exception e) {
1763             Slog.e(TAG, "isProviderEnabled got exception:", e);
1764             return false;
1765         }
1766     }
1767 
reportLocation(Location location, boolean passive)1768     public void reportLocation(Location location, boolean passive) {
1769         if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1770                 != PackageManager.PERMISSION_GRANTED) {
1771             throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
1772         }
1773 
1774         mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1775         Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
1776         m.arg1 = (passive ? 1 : 0);
1777         mLocationHandler.sendMessageAtFrontOfQueue(m);
1778     }
1779 
_isProviderEnabledLocked(String provider)1780     private boolean _isProviderEnabledLocked(String provider) {
1781         checkPermissionsSafe(provider, null);
1782 
1783         LocationProviderInterface p = mProvidersByName.get(provider);
1784         if (p == null) {
1785             return false;
1786         }
1787         return isAllowedBySettingsLocked(provider);
1788     }
1789 
getLastKnownLocation(String provider)1790     public Location getLastKnownLocation(String provider) {
1791         if (LOCAL_LOGV) {
1792             Slog.v(TAG, "getLastKnownLocation: " + provider);
1793         }
1794         try {
1795             synchronized (mLock) {
1796                 return _getLastKnownLocationLocked(provider);
1797             }
1798         } catch (SecurityException se) {
1799             throw se;
1800         } catch (Exception e) {
1801             Slog.e(TAG, "getLastKnownLocation got exception:", e);
1802             return null;
1803         }
1804     }
1805 
_getLastKnownLocationLocked(String provider)1806     private Location _getLastKnownLocationLocked(String provider) {
1807         checkPermissionsSafe(provider, null);
1808 
1809         LocationProviderInterface p = mProvidersByName.get(provider);
1810         if (p == null) {
1811             return null;
1812         }
1813 
1814         if (!isAllowedBySettingsLocked(provider)) {
1815             return null;
1816         }
1817 
1818         return mLastKnownLocation.get(provider);
1819     }
1820 
shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record)1821     private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1822         // Always broadcast the first update
1823         if (lastLoc == null) {
1824             return true;
1825         }
1826 
1827         // Check whether sufficient time has passed
1828         long minTime = record.mMinTime;
1829         if (loc.getTime() - lastLoc.getTime() < minTime - MAX_PROVIDER_SCHEDULING_JITTER) {
1830             return false;
1831         }
1832 
1833         // Check whether sufficient distance has been traveled
1834         double minDistance = record.mMinDistance;
1835         if (minDistance > 0.0) {
1836             if (loc.distanceTo(lastLoc) <= minDistance) {
1837                 return false;
1838             }
1839         }
1840 
1841         return true;
1842     }
1843 
handleLocationChangedLocked(Location location, boolean passive)1844     private void handleLocationChangedLocked(Location location, boolean passive) {
1845         String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
1846         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1847         if (records == null || records.size() == 0) {
1848             return;
1849         }
1850 
1851         LocationProviderInterface p = mProvidersByName.get(provider);
1852         if (p == null) {
1853             return;
1854         }
1855 
1856         // Update last known location for provider
1857         Location lastLocation = mLastKnownLocation.get(provider);
1858         if (lastLocation == null) {
1859             mLastKnownLocation.put(provider, new Location(location));
1860         } else {
1861             lastLocation.set(location);
1862         }
1863 
1864         // Fetch latest status update time
1865         long newStatusUpdateTime = p.getStatusUpdateTime();
1866 
1867        // Get latest status
1868         Bundle extras = new Bundle();
1869         int status = p.getStatus(extras);
1870 
1871         ArrayList<Receiver> deadReceivers = null;
1872 
1873         // Broadcast location or status to all listeners
1874         final int N = records.size();
1875         for (int i=0; i<N; i++) {
1876             UpdateRecord r = records.get(i);
1877             Receiver receiver = r.mReceiver;
1878             boolean receiverDead = false;
1879 
1880             Location lastLoc = r.mLastFixBroadcast;
1881             if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1882                 if (lastLoc == null) {
1883                     lastLoc = new Location(location);
1884                     r.mLastFixBroadcast = lastLoc;
1885                 } else {
1886                     lastLoc.set(location);
1887                 }
1888                 if (!receiver.callLocationChangedLocked(location)) {
1889                     Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1890                     receiverDead = true;
1891                 }
1892             }
1893 
1894             long prevStatusUpdateTime = r.mLastStatusBroadcast;
1895             if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1896                 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1897 
1898                 r.mLastStatusBroadcast = newStatusUpdateTime;
1899                 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1900                     receiverDead = true;
1901                     Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1902                 }
1903             }
1904 
1905             // remove receiver if it is dead or we just processed a single shot request
1906             if (receiverDead || r.mSingleShot) {
1907                 if (deadReceivers == null) {
1908                     deadReceivers = new ArrayList<Receiver>();
1909                 }
1910                 if (!deadReceivers.contains(receiver)) {
1911                     deadReceivers.add(receiver);
1912                 }
1913             }
1914         }
1915 
1916         if (deadReceivers != null) {
1917             for (int i=deadReceivers.size()-1; i>=0; i--) {
1918                 removeUpdatesLocked(deadReceivers.get(i));
1919             }
1920         }
1921     }
1922 
1923     private class LocationWorkerHandler extends Handler {
1924 
1925         @Override
handleMessage(Message msg)1926         public void handleMessage(Message msg) {
1927             try {
1928                 if (msg.what == MESSAGE_LOCATION_CHANGED) {
1929                     // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
1930 
1931                     synchronized (mLock) {
1932                         Location location = (Location) msg.obj;
1933                         String provider = location.getProvider();
1934                         boolean passive = (msg.arg1 == 1);
1935 
1936                         if (!passive) {
1937                             // notify other providers of the new location
1938                             for (int i = mProviders.size() - 1; i >= 0; i--) {
1939                                 LocationProviderInterface p = mProviders.get(i);
1940                                 if (!provider.equals(p.getName())) {
1941                                     p.updateLocation(location);
1942                                 }
1943                             }
1944                         }
1945 
1946                         if (isAllowedBySettingsLocked(provider)) {
1947                             handleLocationChangedLocked(location, passive);
1948                         }
1949                     }
1950                 } else if (msg.what == MESSAGE_PACKAGE_UPDATED) {
1951                     String packageName = (String) msg.obj;
1952 
1953                     // reconnect to external providers if there is a better package
1954                     if (mNetworkLocationProviderPackageName != null &&
1955                             mPackageManager.resolveService(
1956                             new Intent(LocationProviderProxy.SERVICE_ACTION)
1957                             .setPackage(packageName), 0) != null) {
1958                         // package implements service, perform full check
1959                         String bestPackage = findBestPackage(
1960                                 LocationProviderProxy.SERVICE_ACTION,
1961                                 mNetworkLocationProviderPackageName);
1962                         if (packageName.equals(bestPackage)) {
1963                             mNetworkLocationProvider.reconnect(bestPackage);
1964                             mNetworkLocationProviderPackageName = packageName;
1965                         }
1966                     }
1967                     if (mGeocodeProviderPackageName != null &&
1968                             mPackageManager.resolveService(
1969                             new Intent(GeocoderProxy.SERVICE_ACTION)
1970                             .setPackage(packageName), 0) != null) {
1971                         // package implements service, perform full check
1972                         String bestPackage = findBestPackage(
1973                                 GeocoderProxy.SERVICE_ACTION,
1974                                 mGeocodeProviderPackageName);
1975                         if (packageName.equals(bestPackage)) {
1976                             mGeocodeProvider.reconnect(bestPackage);
1977                             mGeocodeProviderPackageName = packageName;
1978                         }
1979                     }
1980                 }
1981             } catch (Exception e) {
1982                 // Log, don't crash!
1983                 Slog.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1984             }
1985         }
1986     }
1987 
1988     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1989         @Override
1990         public void onReceive(Context context, Intent intent) {
1991             String action = intent.getAction();
1992             boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART);
1993             if (queryRestart
1994                     || action.equals(Intent.ACTION_PACKAGE_REMOVED)
1995                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
1996                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
1997                 synchronized (mLock) {
1998                     int uidList[] = null;
1999                     if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
2000                         uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
2001                     } else {
2002                         uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)};
2003                     }
2004                     if (uidList == null || uidList.length == 0) {
2005                         return;
2006                     }
2007                     for (int uid : uidList) {
2008                         if (uid >= 0) {
2009                             ArrayList<Receiver> removedRecs = null;
2010                             for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
2011                                 for (int j=i.size()-1; j>=0; j--) {
2012                                     UpdateRecord ur = i.get(j);
2013                                     if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
2014                                         if (queryRestart) {
2015                                             setResultCode(Activity.RESULT_OK);
2016                                             return;
2017                                         }
2018                                         if (removedRecs == null) {
2019                                             removedRecs = new ArrayList<Receiver>();
2020                                         }
2021                                         if (!removedRecs.contains(ur.mReceiver)) {
2022                                             removedRecs.add(ur.mReceiver);
2023                                         }
2024                                     }
2025                                 }
2026                             }
2027                             ArrayList<ProximityAlert> removedAlerts = null;
2028                             for (ProximityAlert i : mProximityAlerts.values()) {
2029                                 if (i.mUid == uid) {
2030                                     if (queryRestart) {
2031                                         setResultCode(Activity.RESULT_OK);
2032                                         return;
2033                                     }
2034                                     if (removedAlerts == null) {
2035                                         removedAlerts = new ArrayList<ProximityAlert>();
2036                                     }
2037                                     if (!removedAlerts.contains(i)) {
2038                                         removedAlerts.add(i);
2039                                     }
2040                                 }
2041                             }
2042                             if (removedRecs != null) {
2043                                 for (int i=removedRecs.size()-1; i>=0; i--) {
2044                                     removeUpdatesLocked(removedRecs.get(i));
2045                                 }
2046                             }
2047                             if (removedAlerts != null) {
2048                                 for (int i=removedAlerts.size()-1; i>=0; i--) {
2049                                     removeProximityAlertLocked(removedAlerts.get(i).mIntent);
2050                                 }
2051                             }
2052                         }
2053                     }
2054                 }
2055             } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
2056                 boolean noConnectivity =
2057                     intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
2058                 if (!noConnectivity) {
2059                     mNetworkState = LocationProvider.AVAILABLE;
2060                 } else {
2061                     mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
2062                 }
2063 
2064                 final ConnectivityManager connManager = (ConnectivityManager) context
2065                         .getSystemService(Context.CONNECTIVITY_SERVICE);
2066                 final NetworkInfo info = connManager.getActiveNetworkInfo();
2067 
2068                 // Notify location providers of current network state
2069                 synchronized (mLock) {
2070                     for (int i = mProviders.size() - 1; i >= 0; i--) {
2071                         LocationProviderInterface provider = mProviders.get(i);
2072                         if (provider.requiresNetwork()) {
2073                             provider.updateNetworkState(mNetworkState, info);
2074                         }
2075                     }
2076                 }
2077             }
2078         }
2079     };
2080 
2081     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2082         @Override
2083         public void onPackageUpdateFinished(String packageName, int uid) {
2084             // Called by main thread; divert work to LocationWorker.
2085             Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
2086         }
2087         @Override
2088         public void onPackageAdded(String packageName, int uid) {
2089             // Called by main thread; divert work to LocationWorker.
2090             Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
2091         }
2092     };
2093 
2094     // Wake locks
2095 
incrementPendingBroadcasts()2096     private void incrementPendingBroadcasts() {
2097         synchronized (mWakeLock) {
2098             if (mPendingBroadcasts++ == 0) {
2099                 try {
2100                     mWakeLock.acquire();
2101                     log("Acquired wakelock");
2102                 } catch (Exception e) {
2103                     // This is to catch a runtime exception thrown when we try to release an
2104                     // already released lock.
2105                     Slog.e(TAG, "exception in acquireWakeLock()", e);
2106                 }
2107             }
2108         }
2109     }
2110 
decrementPendingBroadcasts()2111     private void decrementPendingBroadcasts() {
2112         synchronized (mWakeLock) {
2113             if (--mPendingBroadcasts == 0) {
2114                 try {
2115                     // Release wake lock
2116                     if (mWakeLock.isHeld()) {
2117                         mWakeLock.release();
2118                         log("Released wakelock");
2119                     } else {
2120                         log("Can't release wakelock again!");
2121                     }
2122                 } catch (Exception e) {
2123                     // This is to catch a runtime exception thrown when we try to release an
2124                     // already released lock.
2125                     Slog.e(TAG, "exception in releaseWakeLock()", e);
2126                 }
2127             }
2128         }
2129     }
2130 
2131     // Geocoder
2132 
geocoderIsPresent()2133     public boolean geocoderIsPresent() {
2134         return mGeocodeProvider != null;
2135     }
2136 
getFromLocation(double latitude, double longitude, int maxResults, GeocoderParams params, List<Address> addrs)2137     public String getFromLocation(double latitude, double longitude, int maxResults,
2138             GeocoderParams params, List<Address> addrs) {
2139         if (mGeocodeProvider != null) {
2140             return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2141                     params, addrs);
2142         }
2143         return null;
2144     }
2145 
2146 
getFromLocationName(String locationName, double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude, double upperRightLongitude, int maxResults, GeocoderParams params, List<Address> addrs)2147     public String getFromLocationName(String locationName,
2148             double lowerLeftLatitude, double lowerLeftLongitude,
2149             double upperRightLatitude, double upperRightLongitude, int maxResults,
2150             GeocoderParams params, List<Address> addrs) {
2151 
2152         if (mGeocodeProvider != null) {
2153             return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2154                     lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2155                     maxResults, params, addrs);
2156         }
2157         return null;
2158     }
2159 
2160     // Mock Providers
2161 
checkMockPermissionsSafe()2162     private void checkMockPermissionsSafe() {
2163         boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2164                 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2165         if (!allowMocks) {
2166             throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2167         }
2168 
2169         if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2170             PackageManager.PERMISSION_GRANTED) {
2171             throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
2172         }
2173     }
2174 
addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy)2175     public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
2176         boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
2177         boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
2178         checkMockPermissionsSafe();
2179 
2180         if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2181             throw new IllegalArgumentException("Cannot mock the passive location provider");
2182         }
2183 
2184         long identity = Binder.clearCallingIdentity();
2185         synchronized (mLock) {
2186             MockProvider provider = new MockProvider(name, this,
2187                 requiresNetwork, requiresSatellite,
2188                 requiresCell, hasMonetaryCost, supportsAltitude,
2189                 supportsSpeed, supportsBearing, powerRequirement, accuracy);
2190             // remove the real provider if we are replacing GPS or network provider
2191             if (LocationManager.GPS_PROVIDER.equals(name)
2192                     || LocationManager.NETWORK_PROVIDER.equals(name)) {
2193                 LocationProviderInterface p = mProvidersByName.get(name);
2194                 if (p != null) {
2195                     p.enableLocationTracking(false);
2196                     removeProvider(p);
2197                 }
2198             }
2199             if (mProvidersByName.get(name) != null) {
2200                 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2201             }
2202             addProvider(provider);
2203             mMockProviders.put(name, provider);
2204             mLastKnownLocation.put(name, null);
2205             updateProvidersLocked();
2206         }
2207         Binder.restoreCallingIdentity(identity);
2208     }
2209 
removeTestProvider(String provider)2210     public void removeTestProvider(String provider) {
2211         checkMockPermissionsSafe();
2212         synchronized (mLock) {
2213             MockProvider mockProvider = mMockProviders.get(provider);
2214             if (mockProvider == null) {
2215                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2216             }
2217             long identity = Binder.clearCallingIdentity();
2218             removeProvider(mProvidersByName.get(provider));
2219             mMockProviders.remove(mockProvider);
2220             // reinstall real provider if we were mocking GPS or network provider
2221             if (LocationManager.GPS_PROVIDER.equals(provider) &&
2222                     mGpsLocationProvider != null) {
2223                 addProvider(mGpsLocationProvider);
2224             } else if (LocationManager.NETWORK_PROVIDER.equals(provider) &&
2225                     mNetworkLocationProvider != null) {
2226                 addProvider(mNetworkLocationProvider);
2227             }
2228             mLastKnownLocation.put(provider, null);
2229             updateProvidersLocked();
2230             Binder.restoreCallingIdentity(identity);
2231         }
2232     }
2233 
setTestProviderLocation(String provider, Location loc)2234     public void setTestProviderLocation(String provider, Location loc) {
2235         checkMockPermissionsSafe();
2236         synchronized (mLock) {
2237             MockProvider mockProvider = mMockProviders.get(provider);
2238             if (mockProvider == null) {
2239                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2240             }
2241             // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2242             long identity = Binder.clearCallingIdentity();
2243             mockProvider.setLocation(loc);
2244             Binder.restoreCallingIdentity(identity);
2245         }
2246     }
2247 
clearTestProviderLocation(String provider)2248     public void clearTestProviderLocation(String provider) {
2249         checkMockPermissionsSafe();
2250         synchronized (mLock) {
2251             MockProvider mockProvider = mMockProviders.get(provider);
2252             if (mockProvider == null) {
2253                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2254             }
2255             mockProvider.clearLocation();
2256         }
2257     }
2258 
setTestProviderEnabled(String provider, boolean enabled)2259     public void setTestProviderEnabled(String provider, boolean enabled) {
2260         checkMockPermissionsSafe();
2261         synchronized (mLock) {
2262             MockProvider mockProvider = mMockProviders.get(provider);
2263             if (mockProvider == null) {
2264                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2265             }
2266             long identity = Binder.clearCallingIdentity();
2267             if (enabled) {
2268                 mockProvider.enable();
2269                 mEnabledProviders.add(provider);
2270                 mDisabledProviders.remove(provider);
2271             } else {
2272                 mockProvider.disable();
2273                 mEnabledProviders.remove(provider);
2274                 mDisabledProviders.add(provider);
2275             }
2276             updateProvidersLocked();
2277             Binder.restoreCallingIdentity(identity);
2278         }
2279     }
2280 
clearTestProviderEnabled(String provider)2281     public void clearTestProviderEnabled(String provider) {
2282         checkMockPermissionsSafe();
2283         synchronized (mLock) {
2284             MockProvider mockProvider = mMockProviders.get(provider);
2285             if (mockProvider == null) {
2286                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2287             }
2288             long identity = Binder.clearCallingIdentity();
2289             mEnabledProviders.remove(provider);
2290             mDisabledProviders.remove(provider);
2291             updateProvidersLocked();
2292             Binder.restoreCallingIdentity(identity);
2293         }
2294     }
2295 
setTestProviderStatus(String provider, int status, Bundle extras, long updateTime)2296     public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2297         checkMockPermissionsSafe();
2298         synchronized (mLock) {
2299             MockProvider mockProvider = mMockProviders.get(provider);
2300             if (mockProvider == null) {
2301                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2302             }
2303             mockProvider.setStatus(status, extras, updateTime);
2304         }
2305     }
2306 
clearTestProviderStatus(String provider)2307     public void clearTestProviderStatus(String provider) {
2308         checkMockPermissionsSafe();
2309         synchronized (mLock) {
2310             MockProvider mockProvider = mMockProviders.get(provider);
2311             if (mockProvider == null) {
2312                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2313             }
2314             mockProvider.clearStatus();
2315         }
2316     }
2317 
log(String log)2318     private void log(String log) {
2319         if (Log.isLoggable(TAG, Log.VERBOSE)) {
2320             Slog.d(TAG, log);
2321         }
2322     }
2323 
dump(FileDescriptor fd, PrintWriter pw, String[] args)2324     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2325         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2326                 != PackageManager.PERMISSION_GRANTED) {
2327             pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2328                     + Binder.getCallingPid()
2329                     + ", uid=" + Binder.getCallingUid());
2330             return;
2331         }
2332 
2333         synchronized (mLock) {
2334             pw.println("Current Location Manager state:");
2335             pw.println("  sProvidersLoaded=" + sProvidersLoaded);
2336             pw.println("  Listeners:");
2337             int N = mReceivers.size();
2338             for (int i=0; i<N; i++) {
2339                 pw.println("    " + mReceivers.get(i));
2340             }
2341             pw.println("  Location Listeners:");
2342             for (Receiver i : mReceivers.values()) {
2343                 pw.println("    " + i + ":");
2344                 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
2345                     pw.println("      " + j.getKey() + ":");
2346                     j.getValue().dump(pw, "        ");
2347                 }
2348             }
2349             pw.println("  Records by Provider:");
2350             for (Map.Entry<String, ArrayList<UpdateRecord>> i
2351                     : mRecordsByProvider.entrySet()) {
2352                 pw.println("    " + i.getKey() + ":");
2353                 for (UpdateRecord j : i.getValue()) {
2354                     pw.println("      " + j + ":");
2355                     j.dump(pw, "        ");
2356                 }
2357             }
2358             pw.println("  Last Known Locations:");
2359             for (Map.Entry<String, Location> i
2360                     : mLastKnownLocation.entrySet()) {
2361                 pw.println("    " + i.getKey() + ":");
2362                 i.getValue().dump(new PrintWriterPrinter(pw), "      ");
2363             }
2364             if (mProximityAlerts.size() > 0) {
2365                 pw.println("  Proximity Alerts:");
2366                 for (Map.Entry<PendingIntent, ProximityAlert> i
2367                         : mProximityAlerts.entrySet()) {
2368                     pw.println("    " + i.getKey() + ":");
2369                     i.getValue().dump(pw, "      ");
2370                 }
2371             }
2372             if (mProximitiesEntered.size() > 0) {
2373                 pw.println("  Proximities Entered:");
2374                 for (ProximityAlert i : mProximitiesEntered) {
2375                     pw.println("    " + i + ":");
2376                     i.dump(pw, "      ");
2377                 }
2378             }
2379             pw.println("  mProximityReceiver=" + mProximityReceiver);
2380             pw.println("  mProximityListener=" + mProximityListener);
2381             if (mEnabledProviders.size() > 0) {
2382                 pw.println("  Enabled Providers:");
2383                 for (String i : mEnabledProviders) {
2384                     pw.println("    " + i);
2385                 }
2386 
2387             }
2388             if (mDisabledProviders.size() > 0) {
2389                 pw.println("  Disabled Providers:");
2390                 for (String i : mDisabledProviders) {
2391                     pw.println("    " + i);
2392                 }
2393 
2394             }
2395             if (mMockProviders.size() > 0) {
2396                 pw.println("  Mock Providers:");
2397                 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2398                     i.getValue().dump(pw, "      ");
2399                 }
2400             }
2401             for (LocationProviderInterface provider: mProviders) {
2402                 String state = provider.getInternalState();
2403                 if (state != null) {
2404                     pw.println(provider.getName() + " Internal State:");
2405                     pw.write(state);
2406                 }
2407             }
2408         }
2409     }
2410 }
2411