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