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.AppOpsManager;
     20 import android.app.PendingIntent;
     21 import android.content.BroadcastReceiver;
     22 import android.content.ContentResolver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.content.pm.ApplicationInfo;
     27 import android.content.pm.PackageInfo;
     28 import android.content.pm.PackageManager;
     29 import android.content.pm.PackageManager.NameNotFoundException;
     30 import android.content.pm.ResolveInfo;
     31 import android.content.pm.Signature;
     32 import android.content.res.Resources;
     33 import android.database.ContentObserver;
     34 import android.location.Address;
     35 import android.location.Criteria;
     36 import android.location.GeocoderParams;
     37 import android.location.Geofence;
     38 import android.location.IGpsStatusListener;
     39 import android.location.IGpsStatusProvider;
     40 import android.location.ILocationListener;
     41 import android.location.ILocationManager;
     42 import android.location.INetInitiatedListener;
     43 import android.location.Location;
     44 import android.location.LocationManager;
     45 import android.location.LocationProvider;
     46 import android.location.LocationRequest;
     47 import android.os.Binder;
     48 import android.os.Bundle;
     49 import android.os.Handler;
     50 import android.os.IBinder;
     51 import android.os.Looper;
     52 import android.os.Message;
     53 import android.os.PowerManager;
     54 import android.os.Process;
     55 import android.os.RemoteException;
     56 import android.os.SystemClock;
     57 import android.os.UserHandle;
     58 import android.os.WorkSource;
     59 import android.provider.Settings;
     60 import android.util.Log;
     61 import android.util.Slog;
     62 import com.android.internal.content.PackageMonitor;
     63 import com.android.internal.location.ProviderProperties;
     64 import com.android.internal.location.ProviderRequest;
     65 import com.android.internal.os.BackgroundThread;
     66 import com.android.server.location.FlpHardwareProvider;
     67 import com.android.server.location.FusedProxy;
     68 import com.android.server.location.GeocoderProxy;
     69 import com.android.server.location.GeofenceProxy;
     70 import com.android.server.location.GeofenceManager;
     71 import com.android.server.location.GpsLocationProvider;
     72 import com.android.server.location.LocationBlacklist;
     73 import com.android.server.location.LocationFudger;
     74 import com.android.server.location.LocationProviderInterface;
     75 import com.android.server.location.LocationProviderProxy;
     76 import com.android.server.location.MockProvider;
     77 import com.android.server.location.PassiveProvider;
     78 
     79 import java.io.FileDescriptor;
     80 import java.io.PrintWriter;
     81 import java.util.ArrayList;
     82 import java.util.Arrays;
     83 import java.util.HashMap;
     84 import java.util.HashSet;
     85 import java.util.List;
     86 import java.util.Map;
     87 import java.util.Set;
     88 
     89 /**
     90  * The service class that manages LocationProviders and issues location
     91  * updates and alerts.
     92  */
     93 public class LocationManagerService extends ILocationManager.Stub {
     94     private static final String TAG = "LocationManagerService";
     95     public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
     96 
     97     private static final String WAKELOCK_KEY = TAG;
     98 
     99     // Location resolution level: no location data whatsoever
    100     private static final int RESOLUTION_LEVEL_NONE = 0;
    101     // Location resolution level: coarse location data only
    102     private static final int RESOLUTION_LEVEL_COARSE = 1;
    103     // Location resolution level: fine location data
    104     private static final int RESOLUTION_LEVEL_FINE = 2;
    105 
    106     private static final String ACCESS_MOCK_LOCATION =
    107             android.Manifest.permission.ACCESS_MOCK_LOCATION;
    108     private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
    109             android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
    110     private static final String INSTALL_LOCATION_PROVIDER =
    111             android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
    112 
    113     private static final String NETWORK_LOCATION_SERVICE_ACTION =
    114             "com.android.location.service.v3.NetworkLocationProvider";
    115     private static final String FUSED_LOCATION_SERVICE_ACTION =
    116             "com.android.location.service.FusedLocationProvider";
    117 
    118     private static final int MSG_LOCATION_CHANGED = 1;
    119 
    120     private static final long NANOS_PER_MILLI = 1000000L;
    121 
    122     // The maximum interval a location request can have and still be considered "high power".
    123     private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
    124 
    125     // Location Providers may sometimes deliver location updates
    126     // slightly faster that requested - provide grace period so
    127     // we don't unnecessarily filter events that are otherwise on
    128     // time
    129     private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
    130 
    131     private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
    132 
    133     private final Context mContext;
    134     private final AppOpsManager mAppOps;
    135 
    136     // used internally for synchronization
    137     private final Object mLock = new Object();
    138 
    139     // --- fields below are final after systemReady() ---
    140     private LocationFudger mLocationFudger;
    141     private GeofenceManager mGeofenceManager;
    142     private PackageManager mPackageManager;
    143     private PowerManager mPowerManager;
    144     private GeocoderProxy mGeocodeProvider;
    145     private IGpsStatusProvider mGpsStatusProvider;
    146     private INetInitiatedListener mNetInitiatedListener;
    147     private LocationWorkerHandler mLocationHandler;
    148     private PassiveProvider mPassiveProvider;  // track passive provider for special cases
    149     private LocationBlacklist mBlacklist;
    150 
    151     // --- fields below are protected by mLock ---
    152     // Set of providers that are explicitly enabled
    153     private final Set<String> mEnabledProviders = new HashSet<String>();
    154 
    155     // Set of providers that are explicitly disabled
    156     private final Set<String> mDisabledProviders = new HashSet<String>();
    157 
    158     // Mock (test) providers
    159     private final HashMap<String, MockProvider> mMockProviders =
    160             new HashMap<String, MockProvider>();
    161 
    162     // all receivers
    163     private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
    164 
    165     // currently installed providers (with mocks replacing real providers)
    166     private final ArrayList<LocationProviderInterface> mProviders =
    167             new ArrayList<LocationProviderInterface>();
    168 
    169     // real providers, saved here when mocked out
    170     private final HashMap<String, LocationProviderInterface> mRealProviders =
    171             new HashMap<String, LocationProviderInterface>();
    172 
    173     // mapping from provider name to provider
    174     private final HashMap<String, LocationProviderInterface> mProvidersByName =
    175             new HashMap<String, LocationProviderInterface>();
    176 
    177     // mapping from provider name to all its UpdateRecords
    178     private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
    179             new HashMap<String, ArrayList<UpdateRecord>>();
    180 
    181     // mapping from provider name to last known location
    182     private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
    183 
    184     // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
    185     // locations stored here are not fudged for coarse permissions.
    186     private final HashMap<String, Location> mLastLocationCoarseInterval =
    187             new HashMap<String, Location>();
    188 
    189     // all providers that operate over proxy, for authorizing incoming location
    190     private final ArrayList<LocationProviderProxy> mProxyProviders =
    191             new ArrayList<LocationProviderProxy>();
    192 
    193     // current active user on the device - other users are denied location data
    194     private int mCurrentUserId = UserHandle.USER_OWNER;
    195 
    196     public LocationManagerService(Context context) {
    197         super();
    198         mContext = context;
    199         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
    200 
    201         if (D) Log.d(TAG, "Constructed");
    202 
    203         // most startup is deferred until systemReady()
    204     }
    205 
    206     public void systemRunning() {
    207         synchronized (mLock) {
    208             if (D) Log.d(TAG, "systemReady()");
    209 
    210             // fetch package manager
    211             mPackageManager = mContext.getPackageManager();
    212 
    213             // fetch power manager
    214             mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    215 
    216             // prepare worker thread
    217             mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
    218 
    219             // prepare mLocationHandler's dependents
    220             mLocationFudger = new LocationFudger(mContext, mLocationHandler);
    221             mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
    222             mBlacklist.init();
    223             mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
    224 
    225             // Monitor for app ops mode changes.
    226             AppOpsManager.OnOpChangedListener callback
    227                     = new AppOpsManager.OnOpChangedInternalListener() {
    228                 public void onOpChanged(int op, String packageName) {
    229                     synchronized (mLock) {
    230                         for (Receiver receiver : mReceivers.values()) {
    231                             receiver.updateMonitoring(true);
    232                         }
    233                         applyAllProviderRequirementsLocked();
    234                     }
    235                 }
    236             };
    237             mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
    238 
    239             // prepare providers
    240             loadProvidersLocked();
    241             updateProvidersLocked();
    242         }
    243 
    244         // listen for settings changes
    245         mContext.getContentResolver().registerContentObserver(
    246                 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
    247                 new ContentObserver(mLocationHandler) {
    248                     @Override
    249                     public void onChange(boolean selfChange) {
    250                         synchronized (mLock) {
    251                             updateProvidersLocked();
    252                         }
    253                     }
    254                 }, UserHandle.USER_ALL);
    255         mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
    256 
    257         // listen for user change
    258         IntentFilter intentFilter = new IntentFilter();
    259         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
    260 
    261         mContext.registerReceiverAsUser(new BroadcastReceiver() {
    262             @Override
    263             public void onReceive(Context context, Intent intent) {
    264                 String action = intent.getAction();
    265                 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
    266                     switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
    267                 }
    268             }
    269         }, UserHandle.ALL, intentFilter, null, mLocationHandler);
    270     }
    271 
    272     private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
    273         PackageManager pm = mContext.getPackageManager();
    274         String systemPackageName = mContext.getPackageName();
    275         ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
    276 
    277         List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
    278                 new Intent(FUSED_LOCATION_SERVICE_ACTION),
    279                 PackageManager.GET_META_DATA, mCurrentUserId);
    280         for (ResolveInfo rInfo : rInfos) {
    281             String packageName = rInfo.serviceInfo.packageName;
    282 
    283             // Check that the signature is in the list of supported sigs. If it's not in
    284             // this list the standard provider binding logic won't bind to it.
    285             try {
    286                 PackageInfo pInfo;
    287                 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
    288                 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
    289                     Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
    290                             ", but has wrong signature, ignoring");
    291                     continue;
    292                 }
    293             } catch (NameNotFoundException e) {
    294                 Log.e(TAG, "missing package: " + packageName);
    295                 continue;
    296             }
    297 
    298             // Get the version info
    299             if (rInfo.serviceInfo.metaData == null) {
    300                 Log.w(TAG, "Found fused provider without metadata: " + packageName);
    301                 continue;
    302             }
    303 
    304             int version = rInfo.serviceInfo.metaData.getInt(
    305                     ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
    306             if (version == 0) {
    307                 // This should be the fallback fused location provider.
    308 
    309                 // Make sure it's in the system partition.
    310                 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
    311                     if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
    312                     continue;
    313                 }
    314 
    315                 // Check that the fallback is signed the same as the OS
    316                 // as a proxy for coreApp="true"
    317                 if (pm.checkSignatures(systemPackageName, packageName)
    318                         != PackageManager.SIGNATURE_MATCH) {
    319                     if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
    320                             + packageName);
    321                     continue;
    322                 }
    323 
    324                 // Found a valid fallback.
    325                 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
    326                 return;
    327             } else {
    328                 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
    329             }
    330         }
    331 
    332         throw new IllegalStateException("Unable to find a fused location provider that is in the "
    333                 + "system partition with version 0 and signed with the platform certificate. "
    334                 + "Such a package is needed to provide a default fused location provider in the "
    335                 + "event that no other fused location provider has been installed or is currently "
    336                 + "available. For example, coreOnly boot mode when decrypting the data "
    337                 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
    338     }
    339 
    340     private void loadProvidersLocked() {
    341         // create a passive location provider, which is always enabled
    342         PassiveProvider passiveProvider = new PassiveProvider(this);
    343         addProviderLocked(passiveProvider);
    344         mEnabledProviders.add(passiveProvider.getName());
    345         mPassiveProvider = passiveProvider;
    346         // Create a gps location provider
    347         GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
    348                 mLocationHandler.getLooper());
    349 
    350         if (GpsLocationProvider.isSupported()) {
    351             mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
    352             mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
    353             addProviderLocked(gpsProvider);
    354             mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
    355         }
    356 
    357         /*
    358         Load package name(s) containing location provider support.
    359         These packages can contain services implementing location providers:
    360         Geocoder Provider, Network Location Provider, and
    361         Fused Location Provider. They will each be searched for
    362         service components implementing these providers.
    363         The location framework also has support for installation
    364         of new location providers at run-time. The new package does not
    365         have to be explicitly listed here, however it must have a signature
    366         that matches the signature of at least one package on this list.
    367         */
    368         Resources resources = mContext.getResources();
    369         ArrayList<String> providerPackageNames = new ArrayList<String>();
    370         String[] pkgs = resources.getStringArray(
    371                 com.android.internal.R.array.config_locationProviderPackageNames);
    372         if (D) Log.d(TAG, "certificates for location providers pulled from: " +
    373                 Arrays.toString(pkgs));
    374         if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
    375 
    376         ensureFallbackFusedProviderPresentLocked(providerPackageNames);
    377 
    378         // bind to network provider
    379         LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
    380                 mContext,
    381                 LocationManager.NETWORK_PROVIDER,
    382                 NETWORK_LOCATION_SERVICE_ACTION,
    383                 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
    384                 com.android.internal.R.string.config_networkLocationProviderPackageName,
    385                 com.android.internal.R.array.config_locationProviderPackageNames,
    386                 mLocationHandler);
    387         if (networkProvider != null) {
    388             mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
    389             mProxyProviders.add(networkProvider);
    390             addProviderLocked(networkProvider);
    391         } else {
    392             Slog.w(TAG,  "no network location provider found");
    393         }
    394 
    395         // bind to fused provider
    396         LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
    397                 mContext,
    398                 LocationManager.FUSED_PROVIDER,
    399                 FUSED_LOCATION_SERVICE_ACTION,
    400                 com.android.internal.R.bool.config_enableFusedLocationOverlay,
    401                 com.android.internal.R.string.config_fusedLocationProviderPackageName,
    402                 com.android.internal.R.array.config_locationProviderPackageNames,
    403                 mLocationHandler);
    404         if (fusedLocationProvider != null) {
    405             addProviderLocked(fusedLocationProvider);
    406             mProxyProviders.add(fusedLocationProvider);
    407             mEnabledProviders.add(fusedLocationProvider.getName());
    408             mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
    409         } else {
    410             Slog.e(TAG, "no fused location provider found",
    411                     new IllegalStateException("Location service needs a fused location provider"));
    412         }
    413 
    414         // bind to geocoder provider
    415         mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
    416                 com.android.internal.R.bool.config_enableGeocoderOverlay,
    417                 com.android.internal.R.string.config_geocoderProviderPackageName,
    418                 com.android.internal.R.array.config_locationProviderPackageNames,
    419                 mLocationHandler);
    420         if (mGeocodeProvider == null) {
    421             Slog.e(TAG,  "no geocoder provider found");
    422         }
    423 
    424         // bind to fused provider
    425         FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
    426         FusedProxy fusedProxy = FusedProxy.createAndBind(
    427                 mContext,
    428                 mLocationHandler,
    429                 flpHardwareProvider.getLocationHardware(),
    430                 com.android.internal.R.bool.config_enableFusedLocationOverlay,
    431                 com.android.internal.R.string.config_fusedLocationProviderPackageName,
    432                 com.android.internal.R.array.config_locationProviderPackageNames);
    433         if(fusedProxy == null) {
    434             Slog.e(TAG, "No FusedProvider found.");
    435         }
    436 
    437         // bind to geofence provider
    438         GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
    439                 com.android.internal.R.bool.config_enableGeofenceOverlay,
    440                 com.android.internal.R.string.config_geofenceProviderPackageName,
    441                 com.android.internal.R.array.config_locationProviderPackageNames,
    442                 mLocationHandler,
    443                 gpsProvider.getGpsGeofenceProxy(),
    444                 flpHardwareProvider.getGeofenceHardware());
    445         if (provider == null) {
    446             Slog.e(TAG,  "no geofence provider found");
    447         }
    448     }
    449 
    450     /**
    451      * Called when the device's active user changes.
    452      * @param userId the new active user's UserId
    453      */
    454     private void switchUser(int userId) {
    455         mBlacklist.switchUser(userId);
    456         mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
    457         synchronized (mLock) {
    458             mLastLocation.clear();
    459             mLastLocationCoarseInterval.clear();
    460             for (LocationProviderInterface p : mProviders) {
    461                 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
    462             }
    463             mCurrentUserId = userId;
    464             updateProvidersLocked();
    465         }
    466     }
    467 
    468     /**
    469      * A wrapper class holding either an ILocationListener or a PendingIntent to receive
    470      * location updates.
    471      */
    472     private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
    473         final int mUid;  // uid of receiver
    474         final int mPid;  // pid of receiver
    475         final String mPackageName;  // package name of receiver
    476         final int mAllowedResolutionLevel;  // resolution level allowed to receiver
    477 
    478         final ILocationListener mListener;
    479         final PendingIntent mPendingIntent;
    480         final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
    481         final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
    482         final Object mKey;
    483 
    484         final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
    485 
    486         // True if app ops has started monitoring this receiver for locations.
    487         boolean mOpMonitoring;
    488         // True if app ops has started monitoring this receiver for high power (gps) locations.
    489         boolean mOpHighPowerMonitoring;
    490         int mPendingBroadcasts;
    491         PowerManager.WakeLock mWakeLock;
    492 
    493         Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
    494                 String packageName, WorkSource workSource, boolean hideFromAppOps) {
    495             mListener = listener;
    496             mPendingIntent = intent;
    497             if (listener != null) {
    498                 mKey = listener.asBinder();
    499             } else {
    500                 mKey = intent;
    501             }
    502             mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
    503             mUid = uid;
    504             mPid = pid;
    505             mPackageName = packageName;
    506             if (workSource != null && workSource.size() <= 0) {
    507                 workSource = null;
    508             }
    509             mWorkSource = workSource;
    510             mHideFromAppOps = hideFromAppOps;
    511 
    512             updateMonitoring(true);
    513 
    514             // construct/configure wakelock
    515             mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
    516             if (workSource == null) {
    517                 workSource = new WorkSource(mUid, mPackageName);
    518             }
    519             mWakeLock.setWorkSource(workSource);
    520         }
    521 
    522         @Override
    523         public boolean equals(Object otherObj) {
    524             if (otherObj instanceof Receiver) {
    525                 return mKey.equals(((Receiver)otherObj).mKey);
    526             }
    527             return false;
    528         }
    529 
    530         @Override
    531         public int hashCode() {
    532             return mKey.hashCode();
    533         }
    534 
    535         @Override
    536         public String toString() {
    537             StringBuilder s = new StringBuilder();
    538             s.append("Reciever[");
    539             s.append(Integer.toHexString(System.identityHashCode(this)));
    540             if (mListener != null) {
    541                 s.append(" listener");
    542             } else {
    543                 s.append(" intent");
    544             }
    545             for (String p : mUpdateRecords.keySet()) {
    546                 s.append(" ").append(mUpdateRecords.get(p).toString());
    547             }
    548             s.append("]");
    549             return s.toString();
    550         }
    551 
    552         /**
    553          * Update AppOp monitoring for this receiver.
    554          *
    555          * @param allow If true receiver is currently active, if false it's been removed.
    556          */
    557         public void updateMonitoring(boolean allow) {
    558             if (mHideFromAppOps) {
    559                 return;
    560             }
    561 
    562             boolean requestingLocation = false;
    563             boolean requestingHighPowerLocation = false;
    564             if (allow) {
    565                 // See if receiver has any enabled update records.  Also note if any update records
    566                 // are high power (has a high power provider with an interval under a threshold).
    567                 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
    568                     if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
    569                         requestingLocation = true;
    570                         LocationProviderInterface locationProvider
    571                             = mProvidersByName.get(updateRecord.mProvider);
    572                         ProviderProperties properties = locationProvider != null
    573                                 ? locationProvider.getProperties() : null;
    574                         if (properties != null
    575                                 && properties.mPowerRequirement == Criteria.POWER_HIGH
    576                                 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
    577                             requestingHighPowerLocation = true;
    578                             break;
    579                         }
    580                     }
    581                 }
    582             }
    583 
    584             // First update monitoring of any location request (including high power).
    585             mOpMonitoring = updateMonitoring(
    586                     requestingLocation,
    587                     mOpMonitoring,
    588                     AppOpsManager.OP_MONITOR_LOCATION);
    589 
    590             // Now update monitoring of high power requests only.
    591             boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
    592             mOpHighPowerMonitoring = updateMonitoring(
    593                     requestingHighPowerLocation,
    594                     mOpHighPowerMonitoring,
    595                     AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
    596             if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
    597                 // Send an intent to notify that a high power request has been added/removed.
    598                 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
    599                 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    600             }
    601         }
    602 
    603         /**
    604          * Update AppOps monitoring for a single location request and op type.
    605          *
    606          * @param allowMonitoring True if monitoring is allowed for this request/op.
    607          * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
    608          * @param op AppOps code for the op to update.
    609          * @return True if monitoring is on for this request/op after updating.
    610          */
    611         private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
    612                 int op) {
    613             if (!currentlyMonitoring) {
    614                 if (allowMonitoring) {
    615                     return mAppOps.startOpNoThrow(op, mUid, mPackageName)
    616                             == AppOpsManager.MODE_ALLOWED;
    617                 }
    618             } else {
    619                 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
    620                         != AppOpsManager.MODE_ALLOWED) {
    621                     mAppOps.finishOp(op, mUid, mPackageName);
    622                     return false;
    623                 }
    624             }
    625 
    626             return currentlyMonitoring;
    627         }
    628 
    629         public boolean isListener() {
    630             return mListener != null;
    631         }
    632 
    633         public boolean isPendingIntent() {
    634             return mPendingIntent != null;
    635         }
    636 
    637         public ILocationListener getListener() {
    638             if (mListener != null) {
    639                 return mListener;
    640             }
    641             throw new IllegalStateException("Request for non-existent listener");
    642         }
    643 
    644         public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
    645             if (mListener != null) {
    646                 try {
    647                     synchronized (this) {
    648                         // synchronize to ensure incrementPendingBroadcastsLocked()
    649                         // is called before decrementPendingBroadcasts()
    650                         mListener.onStatusChanged(provider, status, extras);
    651                         // call this after broadcasting so we do not increment
    652                         // if we throw an exeption.
    653                         incrementPendingBroadcastsLocked();
    654                     }
    655                 } catch (RemoteException e) {
    656                     return false;
    657                 }
    658             } else {
    659                 Intent statusChanged = new Intent();
    660                 statusChanged.putExtras(new Bundle(extras));
    661                 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
    662                 try {
    663                     synchronized (this) {
    664                         // synchronize to ensure incrementPendingBroadcastsLocked()
    665                         // is called before decrementPendingBroadcasts()
    666                         mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
    667                                 getResolutionPermission(mAllowedResolutionLevel));
    668                         // call this after broadcasting so we do not increment
    669                         // if we throw an exeption.
    670                         incrementPendingBroadcastsLocked();
    671                     }
    672                 } catch (PendingIntent.CanceledException e) {
    673                     return false;
    674                 }
    675             }
    676             return true;
    677         }
    678 
    679         public boolean callLocationChangedLocked(Location location) {
    680             if (mListener != null) {
    681                 try {
    682                     synchronized (this) {
    683                         // synchronize to ensure incrementPendingBroadcastsLocked()
    684                         // is called before decrementPendingBroadcasts()
    685                         mListener.onLocationChanged(new Location(location));
    686                         // call this after broadcasting so we do not increment
    687                         // if we throw an exeption.
    688                         incrementPendingBroadcastsLocked();
    689                     }
    690                 } catch (RemoteException e) {
    691                     return false;
    692                 }
    693             } else {
    694                 Intent locationChanged = new Intent();
    695                 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
    696                 try {
    697                     synchronized (this) {
    698                         // synchronize to ensure incrementPendingBroadcastsLocked()
    699                         // is called before decrementPendingBroadcasts()
    700                         mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
    701                                 getResolutionPermission(mAllowedResolutionLevel));
    702                         // call this after broadcasting so we do not increment
    703                         // if we throw an exeption.
    704                         incrementPendingBroadcastsLocked();
    705                     }
    706                 } catch (PendingIntent.CanceledException e) {
    707                     return false;
    708                 }
    709             }
    710             return true;
    711         }
    712 
    713         public boolean callProviderEnabledLocked(String provider, boolean enabled) {
    714             // First update AppOp monitoring.
    715             // An app may get/lose location access as providers are enabled/disabled.
    716             updateMonitoring(true);
    717 
    718             if (mListener != null) {
    719                 try {
    720                     synchronized (this) {
    721                         // synchronize to ensure incrementPendingBroadcastsLocked()
    722                         // is called before decrementPendingBroadcasts()
    723                         if (enabled) {
    724                             mListener.onProviderEnabled(provider);
    725                         } else {
    726                             mListener.onProviderDisabled(provider);
    727                         }
    728                         // call this after broadcasting so we do not increment
    729                         // if we throw an exeption.
    730                         incrementPendingBroadcastsLocked();
    731                     }
    732                 } catch (RemoteException e) {
    733                     return false;
    734                 }
    735             } else {
    736                 Intent providerIntent = new Intent();
    737                 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
    738                 try {
    739                     synchronized (this) {
    740                         // synchronize to ensure incrementPendingBroadcastsLocked()
    741                         // is called before decrementPendingBroadcasts()
    742                         mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
    743                                 getResolutionPermission(mAllowedResolutionLevel));
    744                         // call this after broadcasting so we do not increment
    745                         // if we throw an exeption.
    746                         incrementPendingBroadcastsLocked();
    747                     }
    748                 } catch (PendingIntent.CanceledException e) {
    749                     return false;
    750                 }
    751             }
    752             return true;
    753         }
    754 
    755         @Override
    756         public void binderDied() {
    757             if (D) Log.d(TAG, "Location listener died");
    758 
    759             synchronized (mLock) {
    760                 removeUpdatesLocked(this);
    761             }
    762             synchronized (this) {
    763                 clearPendingBroadcastsLocked();
    764             }
    765         }
    766 
    767         @Override
    768         public void onSendFinished(PendingIntent pendingIntent, Intent intent,
    769                 int resultCode, String resultData, Bundle resultExtras) {
    770             synchronized (this) {
    771                 decrementPendingBroadcastsLocked();
    772             }
    773         }
    774 
    775         // this must be called while synchronized by caller in a synchronized block
    776         // containing the sending of the broadcaset
    777         private void incrementPendingBroadcastsLocked() {
    778             if (mPendingBroadcasts++ == 0) {
    779                 mWakeLock.acquire();
    780             }
    781         }
    782 
    783         private void decrementPendingBroadcastsLocked() {
    784             if (--mPendingBroadcasts == 0) {
    785                 if (mWakeLock.isHeld()) {
    786                     mWakeLock.release();
    787                 }
    788             }
    789         }
    790 
    791         public void clearPendingBroadcastsLocked() {
    792             if (mPendingBroadcasts > 0) {
    793                 mPendingBroadcasts = 0;
    794                 if (mWakeLock.isHeld()) {
    795                     mWakeLock.release();
    796                 }
    797             }
    798         }
    799     }
    800 
    801     @Override
    802     public void locationCallbackFinished(ILocationListener listener) {
    803         //Do not use getReceiverLocked here as that will add the ILocationListener to
    804         //the receiver list if it is not found.  If it is not found then the
    805         //LocationListener was removed when it had a pending broadcast and should
    806         //not be added back.
    807         synchronized (mLock) {
    808             IBinder binder = listener.asBinder();
    809             Receiver receiver = mReceivers.get(binder);
    810             if (receiver != null) {
    811                 synchronized (receiver) {
    812                     // so wakelock calls will succeed
    813                     long identity = Binder.clearCallingIdentity();
    814                     receiver.decrementPendingBroadcastsLocked();
    815                     Binder.restoreCallingIdentity(identity);
    816                }
    817             }
    818         }
    819     }
    820 
    821     private void addProviderLocked(LocationProviderInterface provider) {
    822         mProviders.add(provider);
    823         mProvidersByName.put(provider.getName(), provider);
    824     }
    825 
    826     private void removeProviderLocked(LocationProviderInterface provider) {
    827         provider.disable();
    828         mProviders.remove(provider);
    829         mProvidersByName.remove(provider.getName());
    830     }
    831 
    832     /**
    833      * Returns "true" if access to the specified location provider is allowed by the current
    834      * user's settings. Access to all location providers is forbidden to non-location-provider
    835      * processes belonging to background users.
    836      *
    837      * @param provider the name of the location provider
    838      * @return
    839      */
    840     private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
    841         if (mEnabledProviders.contains(provider)) {
    842             return true;
    843         }
    844         if (mDisabledProviders.contains(provider)) {
    845             return false;
    846         }
    847         // Use system settings
    848         ContentResolver resolver = mContext.getContentResolver();
    849 
    850         return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
    851     }
    852 
    853     /**
    854      * Returns "true" if access to the specified location provider is allowed by the specified
    855      * user's settings. Access to all location providers is forbidden to non-location-provider
    856      * processes belonging to background users.
    857      *
    858      * @param provider the name of the location provider
    859      * @param uid the requestor's UID
    860      * @return
    861      */
    862     private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
    863         if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) {
    864             return false;
    865         }
    866         return isAllowedByCurrentUserSettingsLocked(provider);
    867     }
    868 
    869     /**
    870      * Returns the permission string associated with the specified resolution level.
    871      *
    872      * @param resolutionLevel the resolution level
    873      * @return the permission string
    874      */
    875     private String getResolutionPermission(int resolutionLevel) {
    876         switch (resolutionLevel) {
    877             case RESOLUTION_LEVEL_FINE:
    878                 return android.Manifest.permission.ACCESS_FINE_LOCATION;
    879             case RESOLUTION_LEVEL_COARSE:
    880                 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
    881             default:
    882                 return null;
    883         }
    884     }
    885 
    886     /**
    887      * Returns the resolution level allowed to the given PID/UID pair.
    888      *
    889      * @param pid the PID
    890      * @param uid the UID
    891      * @return resolution level allowed to the pid/uid pair
    892      */
    893     private int getAllowedResolutionLevel(int pid, int uid) {
    894         if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
    895                 pid, uid) == PackageManager.PERMISSION_GRANTED) {
    896             return RESOLUTION_LEVEL_FINE;
    897         } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
    898                 pid, uid) == PackageManager.PERMISSION_GRANTED) {
    899             return RESOLUTION_LEVEL_COARSE;
    900         } else {
    901             return RESOLUTION_LEVEL_NONE;
    902         }
    903     }
    904 
    905     /**
    906      * Returns the resolution level allowed to the caller
    907      *
    908      * @return resolution level allowed to caller
    909      */
    910     private int getCallerAllowedResolutionLevel() {
    911         return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
    912     }
    913 
    914     /**
    915      * Throw SecurityException if specified resolution level is insufficient to use geofences.
    916      *
    917      * @param allowedResolutionLevel resolution level allowed to caller
    918      */
    919     private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
    920         if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
    921             throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
    922         }
    923     }
    924 
    925     /**
    926      * Return the minimum resolution level required to use the specified location provider.
    927      *
    928      * @param provider the name of the location provider
    929      * @return minimum resolution level required for provider
    930      */
    931     private int getMinimumResolutionLevelForProviderUse(String provider) {
    932         if (LocationManager.GPS_PROVIDER.equals(provider) ||
    933                 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
    934             // gps and passive providers require FINE permission
    935             return RESOLUTION_LEVEL_FINE;
    936         } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
    937                 LocationManager.FUSED_PROVIDER.equals(provider)) {
    938             // network and fused providers are ok with COARSE or FINE
    939             return RESOLUTION_LEVEL_COARSE;
    940         } else {
    941             // mock providers
    942             LocationProviderInterface lp = mMockProviders.get(provider);
    943             if (lp != null) {
    944                 ProviderProperties properties = lp.getProperties();
    945                 if (properties != null) {
    946                     if (properties.mRequiresSatellite) {
    947                         // provider requiring satellites require FINE permission
    948                         return RESOLUTION_LEVEL_FINE;
    949                     } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
    950                         // provider requiring network and or cell require COARSE or FINE
    951                         return RESOLUTION_LEVEL_COARSE;
    952                     }
    953                 }
    954             }
    955         }
    956         return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
    957     }
    958 
    959     /**
    960      * Throw SecurityException if specified resolution level is insufficient to use the named
    961      * location provider.
    962      *
    963      * @param allowedResolutionLevel resolution level allowed to caller
    964      * @param providerName the name of the location provider
    965      */
    966     private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
    967             String providerName) {
    968         int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
    969         if (allowedResolutionLevel < requiredResolutionLevel) {
    970             switch (requiredResolutionLevel) {
    971                 case RESOLUTION_LEVEL_FINE:
    972                     throw new SecurityException("\"" + providerName + "\" location provider " +
    973                             "requires ACCESS_FINE_LOCATION permission.");
    974                 case RESOLUTION_LEVEL_COARSE:
    975                     throw new SecurityException("\"" + providerName + "\" location provider " +
    976                             "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
    977                 default:
    978                     throw new SecurityException("Insufficient permission for \"" + providerName +
    979                             "\" location provider.");
    980             }
    981         }
    982     }
    983 
    984     /**
    985      * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
    986      * for battery).
    987      */
    988     private void checkDeviceStatsAllowed() {
    989         mContext.enforceCallingOrSelfPermission(
    990                 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
    991     }
    992 
    993     private void checkUpdateAppOpsAllowed() {
    994         mContext.enforceCallingOrSelfPermission(
    995                 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
    996     }
    997 
    998     public static int resolutionLevelToOp(int allowedResolutionLevel) {
    999         if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
   1000             if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
   1001                 return AppOpsManager.OP_COARSE_LOCATION;
   1002             } else {
   1003                 return AppOpsManager.OP_FINE_LOCATION;
   1004             }
   1005         }
   1006         return -1;
   1007     }
   1008 
   1009     boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
   1010         int op = resolutionLevelToOp(allowedResolutionLevel);
   1011         if (op >= 0) {
   1012             if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
   1013                 return false;
   1014             }
   1015         }
   1016         return true;
   1017     }
   1018 
   1019     boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
   1020         int op = resolutionLevelToOp(allowedResolutionLevel);
   1021         if (op >= 0) {
   1022             if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
   1023                 return false;
   1024             }
   1025         }
   1026         return true;
   1027     }
   1028 
   1029     /**
   1030      * Returns all providers by name, including passive, but excluding
   1031      * fused, also including ones that are not permitted to
   1032      * be accessed by the calling activity or are currently disabled.
   1033      */
   1034     @Override
   1035     public List<String> getAllProviders() {
   1036         ArrayList<String> out;
   1037         synchronized (mLock) {
   1038             out = new ArrayList<String>(mProviders.size());
   1039             for (LocationProviderInterface provider : mProviders) {
   1040                 String name = provider.getName();
   1041                 if (LocationManager.FUSED_PROVIDER.equals(name)) {
   1042                     continue;
   1043                 }
   1044                 out.add(name);
   1045             }
   1046         }
   1047 
   1048         if (D) Log.d(TAG, "getAllProviders()=" + out);
   1049         return out;
   1050     }
   1051 
   1052     /**
   1053      * Return all providers by name, that match criteria and are optionally
   1054      * enabled.
   1055      * Can return passive provider, but never returns fused provider.
   1056      */
   1057     @Override
   1058     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
   1059         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
   1060         ArrayList<String> out;
   1061         int uid = Binder.getCallingUid();;
   1062         long identity = Binder.clearCallingIdentity();
   1063         try {
   1064             synchronized (mLock) {
   1065                 out = new ArrayList<String>(mProviders.size());
   1066                 for (LocationProviderInterface provider : mProviders) {
   1067                     String name = provider.getName();
   1068                     if (LocationManager.FUSED_PROVIDER.equals(name)) {
   1069                         continue;
   1070                     }
   1071                     if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
   1072                         if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
   1073                             continue;
   1074                         }
   1075                         if (criteria != null && !LocationProvider.propertiesMeetCriteria(
   1076                                 name, provider.getProperties(), criteria)) {
   1077                             continue;
   1078                         }
   1079                         out.add(name);
   1080                     }
   1081                 }
   1082             }
   1083         } finally {
   1084             Binder.restoreCallingIdentity(identity);
   1085         }
   1086 
   1087         if (D) Log.d(TAG, "getProviders()=" + out);
   1088         return out;
   1089     }
   1090 
   1091     /**
   1092      * Return the name of the best provider given a Criteria object.
   1093      * This method has been deprecated from the public API,
   1094      * and the whole LocationProvider (including #meetsCriteria)
   1095      * has been deprecated as well. So this method now uses
   1096      * some simplified logic.
   1097      */
   1098     @Override
   1099     public String getBestProvider(Criteria criteria, boolean enabledOnly) {
   1100         String result = null;
   1101 
   1102         List<String> providers = getProviders(criteria, enabledOnly);
   1103         if (!providers.isEmpty()) {
   1104             result = pickBest(providers);
   1105             if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
   1106             return result;
   1107         }
   1108         providers = getProviders(null, enabledOnly);
   1109         if (!providers.isEmpty()) {
   1110             result = pickBest(providers);
   1111             if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
   1112             return result;
   1113         }
   1114 
   1115         if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
   1116         return null;
   1117     }
   1118 
   1119     private String pickBest(List<String> providers) {
   1120         if (providers.contains(LocationManager.GPS_PROVIDER)) {
   1121             return LocationManager.GPS_PROVIDER;
   1122         } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
   1123             return LocationManager.NETWORK_PROVIDER;
   1124         } else {
   1125             return providers.get(0);
   1126         }
   1127     }
   1128 
   1129     @Override
   1130     public boolean providerMeetsCriteria(String provider, Criteria criteria) {
   1131         LocationProviderInterface p = mProvidersByName.get(provider);
   1132         if (p == null) {
   1133             throw new IllegalArgumentException("provider=" + provider);
   1134         }
   1135 
   1136         boolean result = LocationProvider.propertiesMeetCriteria(
   1137                 p.getName(), p.getProperties(), criteria);
   1138         if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
   1139         return result;
   1140     }
   1141 
   1142     private void updateProvidersLocked() {
   1143         boolean changesMade = false;
   1144         for (int i = mProviders.size() - 1; i >= 0; i--) {
   1145             LocationProviderInterface p = mProviders.get(i);
   1146             boolean isEnabled = p.isEnabled();
   1147             String name = p.getName();
   1148             boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
   1149             if (isEnabled && !shouldBeEnabled) {
   1150                 updateProviderListenersLocked(name, false, mCurrentUserId);
   1151                 changesMade = true;
   1152             } else if (!isEnabled && shouldBeEnabled) {
   1153                 updateProviderListenersLocked(name, true, mCurrentUserId);
   1154                 changesMade = true;
   1155             }
   1156         }
   1157         if (changesMade) {
   1158             mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
   1159                     UserHandle.ALL);
   1160             mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
   1161                     UserHandle.ALL);
   1162         }
   1163     }
   1164 
   1165     private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
   1166         int listeners = 0;
   1167 
   1168         LocationProviderInterface p = mProvidersByName.get(provider);
   1169         if (p == null) return;
   1170 
   1171         ArrayList<Receiver> deadReceivers = null;
   1172 
   1173         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
   1174         if (records != null) {
   1175             final int N = records.size();
   1176             for (int i = 0; i < N; i++) {
   1177                 UpdateRecord record = records.get(i);
   1178                 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
   1179                     // Sends a notification message to the receiver
   1180                     if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
   1181                         if (deadReceivers == null) {
   1182                             deadReceivers = new ArrayList<Receiver>();
   1183                         }
   1184                         deadReceivers.add(record.mReceiver);
   1185                     }
   1186                     listeners++;
   1187                 }
   1188             }
   1189         }
   1190 
   1191         if (deadReceivers != null) {
   1192             for (int i = deadReceivers.size() - 1; i >= 0; i--) {
   1193                 removeUpdatesLocked(deadReceivers.get(i));
   1194             }
   1195         }
   1196 
   1197         if (enabled) {
   1198             p.enable();
   1199             if (listeners > 0) {
   1200                 applyRequirementsLocked(provider);
   1201             }
   1202         } else {
   1203             p.disable();
   1204         }
   1205     }
   1206 
   1207     private void applyRequirementsLocked(String provider) {
   1208         LocationProviderInterface p = mProvidersByName.get(provider);
   1209         if (p == null) return;
   1210 
   1211         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
   1212         WorkSource worksource = new WorkSource();
   1213         ProviderRequest providerRequest = new ProviderRequest();
   1214 
   1215         if (records != null) {
   1216             for (UpdateRecord record : records) {
   1217                 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
   1218                     if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
   1219                             record.mReceiver.mAllowedResolutionLevel)) {
   1220                         LocationRequest locationRequest = record.mRequest;
   1221                         providerRequest.locationRequests.add(locationRequest);
   1222                         if (locationRequest.getInterval() < providerRequest.interval) {
   1223                             providerRequest.reportLocation = true;
   1224                             providerRequest.interval = locationRequest.getInterval();
   1225                         }
   1226                     }
   1227                 }
   1228             }
   1229 
   1230             if (providerRequest.reportLocation) {
   1231                 // calculate who to blame for power
   1232                 // This is somewhat arbitrary. We pick a threshold interval
   1233                 // that is slightly higher that the minimum interval, and
   1234                 // spread the blame across all applications with a request
   1235                 // under that threshold.
   1236                 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
   1237                 for (UpdateRecord record : records) {
   1238                     if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
   1239                         LocationRequest locationRequest = record.mRequest;
   1240                         if (locationRequest.getInterval() <= thresholdInterval) {
   1241                             if (record.mReceiver.mWorkSource != null
   1242                                     && record.mReceiver.mWorkSource.size() > 0
   1243                                     && record.mReceiver.mWorkSource.getName(0) != null) {
   1244                                 // Assign blame to another work source.
   1245                                 // Can only assign blame if the WorkSource contains names.
   1246                                 worksource.add(record.mReceiver.mWorkSource);
   1247                             } else {
   1248                                 // Assign blame to caller.
   1249                                 worksource.add(
   1250                                         record.mReceiver.mUid,
   1251                                         record.mReceiver.mPackageName);
   1252                             }
   1253                         }
   1254                     }
   1255                 }
   1256             }
   1257         }
   1258 
   1259         if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
   1260         p.setRequest(providerRequest, worksource);
   1261     }
   1262 
   1263     private class UpdateRecord {
   1264         final String mProvider;
   1265         final LocationRequest mRequest;
   1266         final Receiver mReceiver;
   1267         Location mLastFixBroadcast;
   1268         long mLastStatusBroadcast;
   1269 
   1270         /**
   1271          * Note: must be constructed with lock held.
   1272          */
   1273         UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
   1274             mProvider = provider;
   1275             mRequest = request;
   1276             mReceiver = receiver;
   1277 
   1278             ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
   1279             if (records == null) {
   1280                 records = new ArrayList<UpdateRecord>();
   1281                 mRecordsByProvider.put(provider, records);
   1282             }
   1283             if (!records.contains(this)) {
   1284                 records.add(this);
   1285             }
   1286         }
   1287 
   1288         /**
   1289          * Method to be called when a record will no longer be used.  Calling this multiple times
   1290          * must have the same effect as calling it once.
   1291          */
   1292         void disposeLocked(boolean removeReceiver) {
   1293             // remove from mRecordsByProvider
   1294             ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
   1295             if (globalRecords != null) {
   1296                 globalRecords.remove(this);
   1297             }
   1298 
   1299             if (!removeReceiver) return;  // the caller will handle the rest
   1300 
   1301             // remove from Receiver#mUpdateRecords
   1302             HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
   1303             if (receiverRecords != null) {
   1304                 receiverRecords.remove(this.mProvider);
   1305 
   1306                 // and also remove the Receiver if it has no more update records
   1307                 if (removeReceiver && receiverRecords.size() == 0) {
   1308                     removeUpdatesLocked(mReceiver);
   1309                 }
   1310             }
   1311         }
   1312 
   1313         @Override
   1314         public String toString() {
   1315             StringBuilder s = new StringBuilder();
   1316             s.append("UpdateRecord[");
   1317             s.append(mProvider);
   1318             s.append(' ').append(mReceiver.mPackageName).append('(');
   1319             s.append(mReceiver.mUid).append(')');
   1320             s.append(' ').append(mRequest);
   1321             s.append(']');
   1322             return s.toString();
   1323         }
   1324     }
   1325 
   1326     private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
   1327             String packageName, WorkSource workSource, boolean hideFromAppOps) {
   1328         IBinder binder = listener.asBinder();
   1329         Receiver receiver = mReceivers.get(binder);
   1330         if (receiver == null) {
   1331             receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
   1332                     hideFromAppOps);
   1333             mReceivers.put(binder, receiver);
   1334 
   1335             try {
   1336                 receiver.getListener().asBinder().linkToDeath(receiver, 0);
   1337             } catch (RemoteException e) {
   1338                 Slog.e(TAG, "linkToDeath failed:", e);
   1339                 return null;
   1340             }
   1341         }
   1342         return receiver;
   1343     }
   1344 
   1345     private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
   1346             WorkSource workSource, boolean hideFromAppOps) {
   1347         Receiver receiver = mReceivers.get(intent);
   1348         if (receiver == null) {
   1349             receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
   1350                     hideFromAppOps);
   1351             mReceivers.put(intent, receiver);
   1352         }
   1353         return receiver;
   1354     }
   1355 
   1356     /**
   1357      * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
   1358      * and consistency requirements.
   1359      *
   1360      * @param request the LocationRequest from which to create a sanitized version
   1361      * @return a version of request that meets the given resolution and consistency requirements
   1362      * @hide
   1363      */
   1364     private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
   1365         LocationRequest sanitizedRequest = new LocationRequest(request);
   1366         if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
   1367             switch (sanitizedRequest.getQuality()) {
   1368                 case LocationRequest.ACCURACY_FINE:
   1369                     sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
   1370                     break;
   1371                 case LocationRequest.POWER_HIGH:
   1372                     sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
   1373                     break;
   1374             }
   1375             // throttle
   1376             if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
   1377                 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
   1378             }
   1379             if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
   1380                 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
   1381             }
   1382         }
   1383         // make getFastestInterval() the minimum of interval and fastest interval
   1384         if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
   1385             request.setFastestInterval(request.getInterval());
   1386         }
   1387         return sanitizedRequest;
   1388     }
   1389 
   1390     private void checkPackageName(String packageName) {
   1391         if (packageName == null) {
   1392             throw new SecurityException("invalid package name: " + packageName);
   1393         }
   1394         int uid = Binder.getCallingUid();
   1395         String[] packages = mPackageManager.getPackagesForUid(uid);
   1396         if (packages == null) {
   1397             throw new SecurityException("invalid UID " + uid);
   1398         }
   1399         for (String pkg : packages) {
   1400             if (packageName.equals(pkg)) return;
   1401         }
   1402         throw new SecurityException("invalid package name: " + packageName);
   1403     }
   1404 
   1405     private void checkPendingIntent(PendingIntent intent) {
   1406         if (intent == null) {
   1407             throw new IllegalArgumentException("invalid pending intent: " + intent);
   1408         }
   1409     }
   1410 
   1411     private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
   1412             int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
   1413         if (intent == null && listener == null) {
   1414             throw new IllegalArgumentException("need either listener or intent");
   1415         } else if (intent != null && listener != null) {
   1416             throw new IllegalArgumentException("cannot register both listener and intent");
   1417         } else if (intent != null) {
   1418             checkPendingIntent(intent);
   1419             return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
   1420         } else {
   1421             return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
   1422         }
   1423     }
   1424 
   1425     @Override
   1426     public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
   1427             PendingIntent intent, String packageName) {
   1428         if (request == null) request = DEFAULT_LOCATION_REQUEST;
   1429         checkPackageName(packageName);
   1430         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
   1431         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
   1432                 request.getProvider());
   1433         WorkSource workSource = request.getWorkSource();
   1434         if (workSource != null && workSource.size() > 0) {
   1435             checkDeviceStatsAllowed();
   1436         }
   1437         boolean hideFromAppOps = request.getHideFromAppOps();
   1438         if (hideFromAppOps) {
   1439             checkUpdateAppOpsAllowed();
   1440         }
   1441         LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
   1442 
   1443         final int pid = Binder.getCallingPid();
   1444         final int uid = Binder.getCallingUid();
   1445         // providers may use public location API's, need to clear identity
   1446         long identity = Binder.clearCallingIdentity();
   1447         try {
   1448             // We don't check for MODE_IGNORED here; we will do that when we go to deliver
   1449             // a location.
   1450             checkLocationAccess(uid, packageName, allowedResolutionLevel);
   1451 
   1452             synchronized (mLock) {
   1453                 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
   1454                         packageName, workSource, hideFromAppOps);
   1455                 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
   1456             }
   1457         } finally {
   1458             Binder.restoreCallingIdentity(identity);
   1459         }
   1460     }
   1461 
   1462     private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
   1463             int pid, int uid, String packageName) {
   1464         // Figure out the provider. Either its explicitly request (legacy use cases), or
   1465         // use the fused provider
   1466         if (request == null) request = DEFAULT_LOCATION_REQUEST;
   1467         String name = request.getProvider();
   1468         if (name == null) {
   1469             throw new IllegalArgumentException("provider name must not be null");
   1470         }
   1471 
   1472         if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
   1473                 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
   1474         LocationProviderInterface provider = mProvidersByName.get(name);
   1475         if (provider == null) {
   1476             throw new IllegalArgumentException("provider doesn't exist: " + name);
   1477         }
   1478 
   1479         UpdateRecord record = new UpdateRecord(name, request, receiver);
   1480         UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
   1481         if (oldRecord != null) {
   1482             oldRecord.disposeLocked(false);
   1483         }
   1484 
   1485         boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
   1486         if (isProviderEnabled) {
   1487             applyRequirementsLocked(name);
   1488         } else {
   1489             // Notify the listener that updates are currently disabled
   1490             receiver.callProviderEnabledLocked(name, false);
   1491         }
   1492         // Update the monitoring here just in case multiple location requests were added to the
   1493         // same receiver (this request may be high power and the initial might not have been).
   1494         receiver.updateMonitoring(true);
   1495     }
   1496 
   1497     @Override
   1498     public void removeUpdates(ILocationListener listener, PendingIntent intent,
   1499             String packageName) {
   1500         checkPackageName(packageName);
   1501 
   1502         final int pid = Binder.getCallingPid();
   1503         final int uid = Binder.getCallingUid();
   1504 
   1505         synchronized (mLock) {
   1506             WorkSource workSource = null;
   1507             boolean hideFromAppOps = false;
   1508             Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
   1509                     packageName, workSource, hideFromAppOps);
   1510 
   1511             // providers may use public location API's, need to clear identity
   1512             long identity = Binder.clearCallingIdentity();
   1513             try {
   1514                 removeUpdatesLocked(receiver);
   1515             } finally {
   1516                 Binder.restoreCallingIdentity(identity);
   1517             }
   1518         }
   1519     }
   1520 
   1521     private void removeUpdatesLocked(Receiver receiver) {
   1522         if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
   1523 
   1524         if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
   1525             receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
   1526             synchronized (receiver) {
   1527                 receiver.clearPendingBroadcastsLocked();
   1528             }
   1529         }
   1530 
   1531         receiver.updateMonitoring(false);
   1532 
   1533         // Record which providers were associated with this listener
   1534         HashSet<String> providers = new HashSet<String>();
   1535         HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
   1536         if (oldRecords != null) {
   1537             // Call dispose() on the obsolete update records.
   1538             for (UpdateRecord record : oldRecords.values()) {
   1539                 record.disposeLocked(false);
   1540             }
   1541             // Accumulate providers
   1542             providers.addAll(oldRecords.keySet());
   1543         }
   1544 
   1545         // update provider
   1546         for (String provider : providers) {
   1547             // If provider is already disabled, don't need to do anything
   1548             if (!isAllowedByCurrentUserSettingsLocked(provider)) {
   1549                 continue;
   1550             }
   1551 
   1552             applyRequirementsLocked(provider);
   1553         }
   1554     }
   1555 
   1556     private void applyAllProviderRequirementsLocked() {
   1557         for (LocationProviderInterface p : mProviders) {
   1558             // If provider is already disabled, don't need to do anything
   1559             if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
   1560                 continue;
   1561             }
   1562 
   1563             applyRequirementsLocked(p.getName());
   1564         }
   1565     }
   1566 
   1567     @Override
   1568     public Location getLastLocation(LocationRequest request, String packageName) {
   1569         if (D) Log.d(TAG, "getLastLocation: " + request);
   1570         if (request == null) request = DEFAULT_LOCATION_REQUEST;
   1571         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
   1572         checkPackageName(packageName);
   1573         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
   1574                 request.getProvider());
   1575         // no need to sanitize this request, as only the provider name is used
   1576 
   1577         final int uid = Binder.getCallingUid();
   1578         final long identity = Binder.clearCallingIdentity();
   1579         try {
   1580             if (mBlacklist.isBlacklisted(packageName)) {
   1581                 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
   1582                         packageName);
   1583                 return null;
   1584             }
   1585 
   1586             if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
   1587                 if (D) Log.d(TAG, "not returning last loc for no op app: " +
   1588                         packageName);
   1589                 return null;
   1590             }
   1591 
   1592             synchronized (mLock) {
   1593                 // Figure out the provider. Either its explicitly request (deprecated API's),
   1594                 // or use the fused provider
   1595                 String name = request.getProvider();
   1596                 if (name == null) name = LocationManager.FUSED_PROVIDER;
   1597                 LocationProviderInterface provider = mProvidersByName.get(name);
   1598                 if (provider == null) return null;
   1599 
   1600                 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
   1601 
   1602                 Location location;
   1603                 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
   1604                     // Make sure that an app with coarse permissions can't get frequent location
   1605                     // updates by calling LocationManager.getLastKnownLocation repeatedly.
   1606                     location = mLastLocationCoarseInterval.get(name);
   1607                 } else {
   1608                     location = mLastLocation.get(name);
   1609                 }
   1610                 if (location == null) {
   1611                     return null;
   1612                 }
   1613                 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
   1614                     Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
   1615                     if (noGPSLocation != null) {
   1616                         return new Location(mLocationFudger.getOrCreate(noGPSLocation));
   1617                     }
   1618                 } else {
   1619                     return new Location(location);
   1620                 }
   1621             }
   1622             return null;
   1623         } finally {
   1624             Binder.restoreCallingIdentity(identity);
   1625         }
   1626     }
   1627 
   1628     @Override
   1629     public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
   1630             String packageName) {
   1631         if (request == null) request = DEFAULT_LOCATION_REQUEST;
   1632         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
   1633         checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
   1634         checkPendingIntent(intent);
   1635         checkPackageName(packageName);
   1636         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
   1637                 request.getProvider());
   1638         LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
   1639 
   1640         if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
   1641 
   1642         // geo-fence manager uses the public location API, need to clear identity
   1643         int uid = Binder.getCallingUid();
   1644         if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
   1645             // temporary measure until geofences work for secondary users
   1646             Log.w(TAG, "proximity alerts are currently available only to the primary user");
   1647             return;
   1648         }
   1649         long identity = Binder.clearCallingIdentity();
   1650         try {
   1651             mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
   1652                     uid, packageName);
   1653         } finally {
   1654             Binder.restoreCallingIdentity(identity);
   1655         }
   1656     }
   1657 
   1658     @Override
   1659     public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
   1660         checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
   1661         checkPendingIntent(intent);
   1662         checkPackageName(packageName);
   1663 
   1664         if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
   1665 
   1666         // geo-fence manager uses the public location API, need to clear identity
   1667         long identity = Binder.clearCallingIdentity();
   1668         try {
   1669             mGeofenceManager.removeFence(geofence, intent);
   1670         } finally {
   1671             Binder.restoreCallingIdentity(identity);
   1672         }
   1673     }
   1674 
   1675 
   1676     @Override
   1677     public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
   1678         if (mGpsStatusProvider == null) {
   1679             return false;
   1680         }
   1681         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
   1682         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
   1683                 LocationManager.GPS_PROVIDER);
   1684 
   1685         final int uid = Binder.getCallingUid();
   1686         final long ident = Binder.clearCallingIdentity();
   1687         try {
   1688             if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
   1689                 return false;
   1690             }
   1691         } finally {
   1692             Binder.restoreCallingIdentity(ident);
   1693         }
   1694 
   1695         try {
   1696             mGpsStatusProvider.addGpsStatusListener(listener);
   1697         } catch (RemoteException e) {
   1698             Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
   1699             return false;
   1700         }
   1701         return true;
   1702     }
   1703 
   1704     @Override
   1705     public void removeGpsStatusListener(IGpsStatusListener listener) {
   1706         synchronized (mLock) {
   1707             try {
   1708                 mGpsStatusProvider.removeGpsStatusListener(listener);
   1709             } catch (Exception e) {
   1710                 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
   1711             }
   1712         }
   1713     }
   1714 
   1715     @Override
   1716     public boolean sendExtraCommand(String provider, String command, Bundle extras) {
   1717         if (provider == null) {
   1718             // throw NullPointerException to remain compatible with previous implementation
   1719             throw new NullPointerException();
   1720         }
   1721         checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
   1722                 provider);
   1723 
   1724         // and check for ACCESS_LOCATION_EXTRA_COMMANDS
   1725         if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
   1726                 != PackageManager.PERMISSION_GRANTED)) {
   1727             throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
   1728         }
   1729 
   1730         synchronized (mLock) {
   1731             LocationProviderInterface p = mProvidersByName.get(provider);
   1732             if (p == null) return false;
   1733 
   1734             return p.sendExtraCommand(command, extras);
   1735         }
   1736     }
   1737 
   1738     @Override
   1739     public boolean sendNiResponse(int notifId, int userResponse) {
   1740         if (Binder.getCallingUid() != Process.myUid()) {
   1741             throw new SecurityException(
   1742                     "calling sendNiResponse from outside of the system is not allowed");
   1743         }
   1744         try {
   1745             return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
   1746         } catch (RemoteException e) {
   1747             Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
   1748             return false;
   1749         }
   1750     }
   1751 
   1752     /**
   1753      * @return null if the provider does not exist
   1754      * @throws SecurityException if the provider is not allowed to be
   1755      * accessed by the caller
   1756      */
   1757     @Override
   1758     public ProviderProperties getProviderProperties(String provider) {
   1759         if (mProvidersByName.get(provider) == null) {
   1760           return null;
   1761         }
   1762 
   1763         checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
   1764                 provider);
   1765 
   1766         LocationProviderInterface p;
   1767         synchronized (mLock) {
   1768             p = mProvidersByName.get(provider);
   1769         }
   1770 
   1771         if (p == null) return null;
   1772         return p.getProperties();
   1773     }
   1774 
   1775     @Override
   1776     public boolean isProviderEnabled(String provider) {
   1777         // TODO: remove this check in next release, see b/10696351
   1778         checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
   1779                 provider);
   1780 
   1781         // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
   1782         // so we discourage its use
   1783         if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
   1784 
   1785         int uid = Binder.getCallingUid();
   1786         long identity = Binder.clearCallingIdentity();
   1787         try {
   1788             synchronized (mLock) {
   1789                 LocationProviderInterface p = mProvidersByName.get(provider);
   1790                 if (p == null) return false;
   1791 
   1792                 return isAllowedByUserSettingsLocked(provider, uid);
   1793             }
   1794         } finally {
   1795             Binder.restoreCallingIdentity(identity);
   1796         }
   1797     }
   1798 
   1799     /**
   1800      * Returns "true" if the UID belongs to a bound location provider.
   1801      *
   1802      * @param uid the uid
   1803      * @return true if uid belongs to a bound location provider
   1804      */
   1805     private boolean isUidALocationProvider(int uid) {
   1806         if (uid == Process.SYSTEM_UID) {
   1807             return true;
   1808         }
   1809         if (mGeocodeProvider != null) {
   1810             if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
   1811         }
   1812         for (LocationProviderProxy proxy : mProxyProviders) {
   1813             if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
   1814         }
   1815         return false;
   1816     }
   1817 
   1818     private void checkCallerIsProvider() {
   1819         if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
   1820                 == PackageManager.PERMISSION_GRANTED) {
   1821             return;
   1822         }
   1823 
   1824         // Previously we only used the INSTALL_LOCATION_PROVIDER
   1825         // check. But that is system or signature
   1826         // protection level which is not flexible enough for
   1827         // providers installed oustide the system image. So
   1828         // also allow providers with a UID matching the
   1829         // currently bound package name
   1830 
   1831         if (isUidALocationProvider(Binder.getCallingUid())) {
   1832             return;
   1833         }
   1834 
   1835         throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
   1836                 "or UID of a currently bound location provider");
   1837     }
   1838 
   1839     private boolean doesPackageHaveUid(int uid, String packageName) {
   1840         if (packageName == null) {
   1841             return false;
   1842         }
   1843         try {
   1844             ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
   1845             if (appInfo.uid != uid) {
   1846                 return false;
   1847             }
   1848         } catch (NameNotFoundException e) {
   1849             return false;
   1850         }
   1851         return true;
   1852     }
   1853 
   1854     @Override
   1855     public void reportLocation(Location location, boolean passive) {
   1856         checkCallerIsProvider();
   1857 
   1858         if (!location.isComplete()) {
   1859             Log.w(TAG, "Dropping incomplete location: " + location);
   1860             return;
   1861         }
   1862 
   1863         mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
   1864         Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
   1865         m.arg1 = (passive ? 1 : 0);
   1866         mLocationHandler.sendMessageAtFrontOfQueue(m);
   1867     }
   1868 
   1869 
   1870     private static boolean shouldBroadcastSafe(
   1871             Location loc, Location lastLoc, UpdateRecord record, long now) {
   1872         // Always broadcast the first update
   1873         if (lastLoc == null) {
   1874             return true;
   1875         }
   1876 
   1877         // Check whether sufficient time has passed
   1878         long minTime = record.mRequest.getFastestInterval();
   1879         long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
   1880                 / NANOS_PER_MILLI;
   1881         if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
   1882             return false;
   1883         }
   1884 
   1885         // Check whether sufficient distance has been traveled
   1886         double minDistance = record.mRequest.getSmallestDisplacement();
   1887         if (minDistance > 0.0) {
   1888             if (loc.distanceTo(lastLoc) <= minDistance) {
   1889                 return false;
   1890             }
   1891         }
   1892 
   1893         // Check whether sufficient number of udpates is left
   1894         if (record.mRequest.getNumUpdates() <= 0) {
   1895             return false;
   1896         }
   1897 
   1898         // Check whether the expiry date has passed
   1899         if (record.mRequest.getExpireAt() < now) {
   1900             return false;
   1901         }
   1902 
   1903         return true;
   1904     }
   1905 
   1906     private void handleLocationChangedLocked(Location location, boolean passive) {
   1907         if (D) Log.d(TAG, "incoming location: " + location);
   1908 
   1909         long now = SystemClock.elapsedRealtime();
   1910         String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
   1911 
   1912         // Skip if the provider is unknown.
   1913         LocationProviderInterface p = mProvidersByName.get(provider);
   1914         if (p == null) return;
   1915 
   1916         // Update last known locations
   1917         Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
   1918         Location lastNoGPSLocation = null;
   1919         Location lastLocation = mLastLocation.get(provider);
   1920         if (lastLocation == null) {
   1921             lastLocation = new Location(provider);
   1922             mLastLocation.put(provider, lastLocation);
   1923         } else {
   1924             lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
   1925             if (noGPSLocation == null && lastNoGPSLocation != null) {
   1926                 // New location has no no-GPS location: adopt last no-GPS location. This is set
   1927                 // directly into location because we do not want to notify COARSE clients.
   1928                 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
   1929             }
   1930         }
   1931         lastLocation.set(location);
   1932 
   1933         // Update last known coarse interval location if enough time has passed.
   1934         Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
   1935         if (lastLocationCoarseInterval == null) {
   1936             lastLocationCoarseInterval = new Location(location);
   1937             mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
   1938         }
   1939         long timeDiffNanos = location.getElapsedRealtimeNanos()
   1940                 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
   1941         if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
   1942             lastLocationCoarseInterval.set(location);
   1943         }
   1944         // Don't ever return a coarse location that is more recent than the allowed update
   1945         // interval (i.e. don't allow an app to keep registering and unregistering for
   1946         // location updates to overcome the minimum interval).
   1947         noGPSLocation =
   1948                 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
   1949 
   1950         // Skip if there are no UpdateRecords for this provider.
   1951         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
   1952         if (records == null || records.size() == 0) return;
   1953 
   1954         // Fetch coarse location
   1955         Location coarseLocation = null;
   1956         if (noGPSLocation != null) {
   1957             coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
   1958         }
   1959 
   1960         // Fetch latest status update time
   1961         long newStatusUpdateTime = p.getStatusUpdateTime();
   1962 
   1963        // Get latest status
   1964         Bundle extras = new Bundle();
   1965         int status = p.getStatus(extras);
   1966 
   1967         ArrayList<Receiver> deadReceivers = null;
   1968         ArrayList<UpdateRecord> deadUpdateRecords = null;
   1969 
   1970         // Broadcast location or status to all listeners
   1971         for (UpdateRecord r : records) {
   1972             Receiver receiver = r.mReceiver;
   1973             boolean receiverDead = false;
   1974 
   1975             int receiverUserId = UserHandle.getUserId(receiver.mUid);
   1976             if (receiverUserId != mCurrentUserId && !isUidALocationProvider(receiver.mUid)) {
   1977                 if (D) {
   1978                     Log.d(TAG, "skipping loc update for background user " + receiverUserId +
   1979                             " (current user: " + mCurrentUserId + ", app: " +
   1980                             receiver.mPackageName + ")");
   1981                 }
   1982                 continue;
   1983             }
   1984 
   1985             if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
   1986                 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
   1987                         receiver.mPackageName);
   1988                 continue;
   1989             }
   1990 
   1991             if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
   1992                     receiver.mAllowedResolutionLevel)) {
   1993                 if (D) Log.d(TAG, "skipping loc update for no op app: " +
   1994                         receiver.mPackageName);
   1995                 continue;
   1996             }
   1997 
   1998             Location notifyLocation = null;
   1999             if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
   2000                 notifyLocation = coarseLocation;  // use coarse location
   2001             } else {
   2002                 notifyLocation = lastLocation;  // use fine location
   2003             }
   2004             if (notifyLocation != null) {
   2005                 Location lastLoc = r.mLastFixBroadcast;
   2006                 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
   2007                     if (lastLoc == null) {
   2008                         lastLoc = new Location(notifyLocation);
   2009                         r.mLastFixBroadcast = lastLoc;
   2010                     } else {
   2011                         lastLoc.set(notifyLocation);
   2012                     }
   2013                     if (!receiver.callLocationChangedLocked(notifyLocation)) {
   2014                         Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
   2015                         receiverDead = true;
   2016                     }
   2017                     r.mRequest.decrementNumUpdates();
   2018                 }
   2019             }
   2020 
   2021             long prevStatusUpdateTime = r.mLastStatusBroadcast;
   2022             if ((newStatusUpdateTime > prevStatusUpdateTime) &&
   2023                     (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
   2024 
   2025                 r.mLastStatusBroadcast = newStatusUpdateTime;
   2026                 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
   2027                     receiverDead = true;
   2028                     Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
   2029                 }
   2030             }
   2031 
   2032             // track expired records
   2033             if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
   2034                 if (deadUpdateRecords == null) {
   2035                     deadUpdateRecords = new ArrayList<UpdateRecord>();
   2036                 }
   2037                 deadUpdateRecords.add(r);
   2038             }
   2039             // track dead receivers
   2040             if (receiverDead) {
   2041                 if (deadReceivers == null) {
   2042                     deadReceivers = new ArrayList<Receiver>();
   2043                 }
   2044                 if (!deadReceivers.contains(receiver)) {
   2045                     deadReceivers.add(receiver);
   2046                 }
   2047             }
   2048         }
   2049 
   2050         // remove dead records and receivers outside the loop
   2051         if (deadReceivers != null) {
   2052             for (Receiver receiver : deadReceivers) {
   2053                 removeUpdatesLocked(receiver);
   2054             }
   2055         }
   2056         if (deadUpdateRecords != null) {
   2057             for (UpdateRecord r : deadUpdateRecords) {
   2058                 r.disposeLocked(true);
   2059             }
   2060             applyRequirementsLocked(provider);
   2061         }
   2062     }
   2063 
   2064     private class LocationWorkerHandler extends Handler {
   2065         public LocationWorkerHandler(Looper looper) {
   2066             super(looper, null, true);
   2067         }
   2068 
   2069         @Override
   2070         public void handleMessage(Message msg) {
   2071             switch (msg.what) {
   2072                 case MSG_LOCATION_CHANGED:
   2073                     handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
   2074                     break;
   2075             }
   2076         }
   2077     }
   2078 
   2079     private boolean isMockProvider(String provider) {
   2080         synchronized (mLock) {
   2081             return mMockProviders.containsKey(provider);
   2082         }
   2083     }
   2084 
   2085     private void handleLocationChanged(Location location, boolean passive) {
   2086         // create a working copy of the incoming Location so that the service can modify it without
   2087         // disturbing the caller's copy
   2088         Location myLocation = new Location(location);
   2089         String provider = myLocation.getProvider();
   2090 
   2091         // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
   2092         // bit if location did not come from a mock provider because passive/fused providers can
   2093         // forward locations from mock providers, and should not grant them legitimacy in doing so.
   2094         if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
   2095             myLocation.setIsFromMockProvider(true);
   2096         }
   2097 
   2098         synchronized (mLock) {
   2099             if (isAllowedByCurrentUserSettingsLocked(provider)) {
   2100                 if (!passive) {
   2101                     // notify passive provider of the new location
   2102                     mPassiveProvider.updateLocation(myLocation);
   2103                 }
   2104                 handleLocationChangedLocked(myLocation, passive);
   2105             }
   2106         }
   2107     }
   2108 
   2109     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
   2110         @Override
   2111         public void onPackageDisappeared(String packageName, int reason) {
   2112             // remove all receivers associated with this package name
   2113             synchronized (mLock) {
   2114                 ArrayList<Receiver> deadReceivers = null;
   2115 
   2116                 for (Receiver receiver : mReceivers.values()) {
   2117                     if (receiver.mPackageName.equals(packageName)) {
   2118                         if (deadReceivers == null) {
   2119                             deadReceivers = new ArrayList<Receiver>();
   2120                         }
   2121                         deadReceivers.add(receiver);
   2122                     }
   2123                 }
   2124 
   2125                 // perform removal outside of mReceivers loop
   2126                 if (deadReceivers != null) {
   2127                     for (Receiver receiver : deadReceivers) {
   2128                         removeUpdatesLocked(receiver);
   2129                     }
   2130                 }
   2131             }
   2132         }
   2133     };
   2134 
   2135     // Geocoder
   2136 
   2137     @Override
   2138     public boolean geocoderIsPresent() {
   2139         return mGeocodeProvider != null;
   2140     }
   2141 
   2142     @Override
   2143     public String getFromLocation(double latitude, double longitude, int maxResults,
   2144             GeocoderParams params, List<Address> addrs) {
   2145         if (mGeocodeProvider != null) {
   2146             return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
   2147                     params, addrs);
   2148         }
   2149         return null;
   2150     }
   2151 
   2152 
   2153     @Override
   2154     public String getFromLocationName(String locationName,
   2155             double lowerLeftLatitude, double lowerLeftLongitude,
   2156             double upperRightLatitude, double upperRightLongitude, int maxResults,
   2157             GeocoderParams params, List<Address> addrs) {
   2158 
   2159         if (mGeocodeProvider != null) {
   2160             return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
   2161                     lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
   2162                     maxResults, params, addrs);
   2163         }
   2164         return null;
   2165     }
   2166 
   2167     // Mock Providers
   2168 
   2169     private void checkMockPermissionsSafe() {
   2170         boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
   2171                 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
   2172         if (!allowMocks) {
   2173             throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
   2174         }
   2175 
   2176         if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
   2177             PackageManager.PERMISSION_GRANTED) {
   2178             throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
   2179         }
   2180     }
   2181 
   2182     @Override
   2183     public void addTestProvider(String name, ProviderProperties properties) {
   2184         checkMockPermissionsSafe();
   2185 
   2186         if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
   2187             throw new IllegalArgumentException("Cannot mock the passive location provider");
   2188         }
   2189 
   2190         long identity = Binder.clearCallingIdentity();
   2191         synchronized (mLock) {
   2192             MockProvider provider = new MockProvider(name, this, properties);
   2193             // remove the real provider if we are replacing GPS or network provider
   2194             if (LocationManager.GPS_PROVIDER.equals(name)
   2195                     || LocationManager.NETWORK_PROVIDER.equals(name)
   2196                     || LocationManager.FUSED_PROVIDER.equals(name)) {
   2197                 LocationProviderInterface p = mProvidersByName.get(name);
   2198                 if (p != null) {
   2199                     removeProviderLocked(p);
   2200                 }
   2201             }
   2202             if (mProvidersByName.get(name) != null) {
   2203                 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
   2204             }
   2205             addProviderLocked(provider);
   2206             mMockProviders.put(name, provider);
   2207             mLastLocation.put(name, null);
   2208             mLastLocationCoarseInterval.put(name, null);
   2209             updateProvidersLocked();
   2210         }
   2211         Binder.restoreCallingIdentity(identity);
   2212     }
   2213 
   2214     @Override
   2215     public void removeTestProvider(String provider) {
   2216         checkMockPermissionsSafe();
   2217         synchronized (mLock) {
   2218             MockProvider mockProvider = mMockProviders.remove(provider);
   2219             if (mockProvider == null) {
   2220                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2221             }
   2222             long identity = Binder.clearCallingIdentity();
   2223             removeProviderLocked(mProvidersByName.get(provider));
   2224 
   2225             // reinstate real provider if available
   2226             LocationProviderInterface realProvider = mRealProviders.get(provider);
   2227             if (realProvider != null) {
   2228                 addProviderLocked(realProvider);
   2229             }
   2230             mLastLocation.put(provider, null);
   2231             mLastLocationCoarseInterval.put(provider, null);
   2232             updateProvidersLocked();
   2233             Binder.restoreCallingIdentity(identity);
   2234         }
   2235     }
   2236 
   2237     @Override
   2238     public void setTestProviderLocation(String provider, Location loc) {
   2239         checkMockPermissionsSafe();
   2240         synchronized (mLock) {
   2241             MockProvider mockProvider = mMockProviders.get(provider);
   2242             if (mockProvider == null) {
   2243                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2244             }
   2245             // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
   2246             long identity = Binder.clearCallingIdentity();
   2247             mockProvider.setLocation(loc);
   2248             Binder.restoreCallingIdentity(identity);
   2249         }
   2250     }
   2251 
   2252     @Override
   2253     public void clearTestProviderLocation(String provider) {
   2254         checkMockPermissionsSafe();
   2255         synchronized (mLock) {
   2256             MockProvider mockProvider = mMockProviders.get(provider);
   2257             if (mockProvider == null) {
   2258                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2259             }
   2260             mockProvider.clearLocation();
   2261         }
   2262     }
   2263 
   2264     @Override
   2265     public void setTestProviderEnabled(String provider, boolean enabled) {
   2266         checkMockPermissionsSafe();
   2267         synchronized (mLock) {
   2268             MockProvider mockProvider = mMockProviders.get(provider);
   2269             if (mockProvider == null) {
   2270                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2271             }
   2272             long identity = Binder.clearCallingIdentity();
   2273             if (enabled) {
   2274                 mockProvider.enable();
   2275                 mEnabledProviders.add(provider);
   2276                 mDisabledProviders.remove(provider);
   2277             } else {
   2278                 mockProvider.disable();
   2279                 mEnabledProviders.remove(provider);
   2280                 mDisabledProviders.add(provider);
   2281             }
   2282             updateProvidersLocked();
   2283             Binder.restoreCallingIdentity(identity);
   2284         }
   2285     }
   2286 
   2287     @Override
   2288     public void clearTestProviderEnabled(String provider) {
   2289         checkMockPermissionsSafe();
   2290         synchronized (mLock) {
   2291             MockProvider mockProvider = mMockProviders.get(provider);
   2292             if (mockProvider == null) {
   2293                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2294             }
   2295             long identity = Binder.clearCallingIdentity();
   2296             mEnabledProviders.remove(provider);
   2297             mDisabledProviders.remove(provider);
   2298             updateProvidersLocked();
   2299             Binder.restoreCallingIdentity(identity);
   2300         }
   2301     }
   2302 
   2303     @Override
   2304     public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
   2305         checkMockPermissionsSafe();
   2306         synchronized (mLock) {
   2307             MockProvider mockProvider = mMockProviders.get(provider);
   2308             if (mockProvider == null) {
   2309                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2310             }
   2311             mockProvider.setStatus(status, extras, updateTime);
   2312         }
   2313     }
   2314 
   2315     @Override
   2316     public void clearTestProviderStatus(String provider) {
   2317         checkMockPermissionsSafe();
   2318         synchronized (mLock) {
   2319             MockProvider mockProvider = mMockProviders.get(provider);
   2320             if (mockProvider == null) {
   2321                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2322             }
   2323             mockProvider.clearStatus();
   2324         }
   2325     }
   2326 
   2327     private void log(String log) {
   2328         if (Log.isLoggable(TAG, Log.VERBOSE)) {
   2329             Slog.d(TAG, log);
   2330         }
   2331     }
   2332 
   2333     @Override
   2334     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2335         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
   2336                 != PackageManager.PERMISSION_GRANTED) {
   2337             pw.println("Permission Denial: can't dump LocationManagerService from from pid="
   2338                     + Binder.getCallingPid()
   2339                     + ", uid=" + Binder.getCallingUid());
   2340             return;
   2341         }
   2342 
   2343         synchronized (mLock) {
   2344             pw.println("Current Location Manager state:");
   2345             pw.println("  Location Listeners:");
   2346             for (Receiver receiver : mReceivers.values()) {
   2347                 pw.println("    " + receiver);
   2348             }
   2349             pw.println("  Records by Provider:");
   2350             for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
   2351                 pw.println("    " + entry.getKey() + ":");
   2352                 for (UpdateRecord record : entry.getValue()) {
   2353                     pw.println("      " + record);
   2354                 }
   2355             }
   2356             pw.println("  Last Known Locations:");
   2357             for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
   2358                 String provider = entry.getKey();
   2359                 Location location = entry.getValue();
   2360                 pw.println("    " + provider + ": " + location);
   2361             }
   2362 
   2363             pw.println("  Last Known Locations Coarse Intervals:");
   2364             for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
   2365                 String provider = entry.getKey();
   2366                 Location location = entry.getValue();
   2367                 pw.println("    " + provider + ": " + location);
   2368             }
   2369 
   2370             mGeofenceManager.dump(pw);
   2371 
   2372             if (mEnabledProviders.size() > 0) {
   2373                 pw.println("  Enabled Providers:");
   2374                 for (String i : mEnabledProviders) {
   2375                     pw.println("    " + i);
   2376                 }
   2377 
   2378             }
   2379             if (mDisabledProviders.size() > 0) {
   2380                 pw.println("  Disabled Providers:");
   2381                 for (String i : mDisabledProviders) {
   2382                     pw.println("    " + i);
   2383                 }
   2384             }
   2385             pw.append("  ");
   2386             mBlacklist.dump(pw);
   2387             if (mMockProviders.size() > 0) {
   2388                 pw.println("  Mock Providers:");
   2389                 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
   2390                     i.getValue().dump(pw, "      ");
   2391                 }
   2392             }
   2393 
   2394             pw.append("  fudger: ");
   2395             mLocationFudger.dump(fd, pw,  args);
   2396 
   2397             if (args.length > 0 && "short".equals(args[0])) {
   2398                 return;
   2399             }
   2400             for (LocationProviderInterface provider: mProviders) {
   2401                 pw.print(provider.getName() + " Internal State");
   2402                 if (provider instanceof LocationProviderProxy) {
   2403                     LocationProviderProxy proxy = (LocationProviderProxy) provider;
   2404                     pw.print(" (" + proxy.getConnectedPackageName() + ")");
   2405                 }
   2406                 pw.println(":");
   2407                 provider.dump(fd, pw, args);
   2408             }
   2409         }
   2410     }
   2411 }
   2412