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                 // If any provider has been disabled, clear all last locations for all providers.
   1152                 // This is to be on the safe side in case a provider has location derived from
   1153                 // this disabled provider.
   1154                 mLastLocation.clear();
   1155                 mLastLocationCoarseInterval.clear();
   1156                 changesMade = true;
   1157             } else if (!isEnabled && shouldBeEnabled) {
   1158                 updateProviderListenersLocked(name, true, mCurrentUserId);
   1159                 changesMade = true;
   1160             }
   1161         }
   1162         if (changesMade) {
   1163             mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
   1164                     UserHandle.ALL);
   1165             mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
   1166                     UserHandle.ALL);
   1167         }
   1168     }
   1169 
   1170     private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
   1171         int listeners = 0;
   1172 
   1173         LocationProviderInterface p = mProvidersByName.get(provider);
   1174         if (p == null) return;
   1175 
   1176         ArrayList<Receiver> deadReceivers = null;
   1177 
   1178         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
   1179         if (records != null) {
   1180             final int N = records.size();
   1181             for (int i = 0; i < N; i++) {
   1182                 UpdateRecord record = records.get(i);
   1183                 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
   1184                     // Sends a notification message to the receiver
   1185                     if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
   1186                         if (deadReceivers == null) {
   1187                             deadReceivers = new ArrayList<Receiver>();
   1188                         }
   1189                         deadReceivers.add(record.mReceiver);
   1190                     }
   1191                     listeners++;
   1192                 }
   1193             }
   1194         }
   1195 
   1196         if (deadReceivers != null) {
   1197             for (int i = deadReceivers.size() - 1; i >= 0; i--) {
   1198                 removeUpdatesLocked(deadReceivers.get(i));
   1199             }
   1200         }
   1201 
   1202         if (enabled) {
   1203             p.enable();
   1204             if (listeners > 0) {
   1205                 applyRequirementsLocked(provider);
   1206             }
   1207         } else {
   1208             p.disable();
   1209         }
   1210     }
   1211 
   1212     private void applyRequirementsLocked(String provider) {
   1213         LocationProviderInterface p = mProvidersByName.get(provider);
   1214         if (p == null) return;
   1215 
   1216         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
   1217         WorkSource worksource = new WorkSource();
   1218         ProviderRequest providerRequest = new ProviderRequest();
   1219 
   1220         if (records != null) {
   1221             for (UpdateRecord record : records) {
   1222                 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
   1223                     if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
   1224                             record.mReceiver.mAllowedResolutionLevel)) {
   1225                         LocationRequest locationRequest = record.mRequest;
   1226                         providerRequest.locationRequests.add(locationRequest);
   1227                         if (locationRequest.getInterval() < providerRequest.interval) {
   1228                             providerRequest.reportLocation = true;
   1229                             providerRequest.interval = locationRequest.getInterval();
   1230                         }
   1231                     }
   1232                 }
   1233             }
   1234 
   1235             if (providerRequest.reportLocation) {
   1236                 // calculate who to blame for power
   1237                 // This is somewhat arbitrary. We pick a threshold interval
   1238                 // that is slightly higher that the minimum interval, and
   1239                 // spread the blame across all applications with a request
   1240                 // under that threshold.
   1241                 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
   1242                 for (UpdateRecord record : records) {
   1243                     if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
   1244                         LocationRequest locationRequest = record.mRequest;
   1245                         if (locationRequest.getInterval() <= thresholdInterval) {
   1246                             if (record.mReceiver.mWorkSource != null
   1247                                     && record.mReceiver.mWorkSource.size() > 0
   1248                                     && record.mReceiver.mWorkSource.getName(0) != null) {
   1249                                 // Assign blame to another work source.
   1250                                 // Can only assign blame if the WorkSource contains names.
   1251                                 worksource.add(record.mReceiver.mWorkSource);
   1252                             } else {
   1253                                 // Assign blame to caller.
   1254                                 worksource.add(
   1255                                         record.mReceiver.mUid,
   1256                                         record.mReceiver.mPackageName);
   1257                             }
   1258                         }
   1259                     }
   1260                 }
   1261             }
   1262         }
   1263 
   1264         if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
   1265         p.setRequest(providerRequest, worksource);
   1266     }
   1267 
   1268     private class UpdateRecord {
   1269         final String mProvider;
   1270         final LocationRequest mRequest;
   1271         final Receiver mReceiver;
   1272         Location mLastFixBroadcast;
   1273         long mLastStatusBroadcast;
   1274 
   1275         /**
   1276          * Note: must be constructed with lock held.
   1277          */
   1278         UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
   1279             mProvider = provider;
   1280             mRequest = request;
   1281             mReceiver = receiver;
   1282 
   1283             ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
   1284             if (records == null) {
   1285                 records = new ArrayList<UpdateRecord>();
   1286                 mRecordsByProvider.put(provider, records);
   1287             }
   1288             if (!records.contains(this)) {
   1289                 records.add(this);
   1290             }
   1291         }
   1292 
   1293         /**
   1294          * Method to be called when a record will no longer be used.  Calling this multiple times
   1295          * must have the same effect as calling it once.
   1296          */
   1297         void disposeLocked(boolean removeReceiver) {
   1298             // remove from mRecordsByProvider
   1299             ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
   1300             if (globalRecords != null) {
   1301                 globalRecords.remove(this);
   1302             }
   1303 
   1304             if (!removeReceiver) return;  // the caller will handle the rest
   1305 
   1306             // remove from Receiver#mUpdateRecords
   1307             HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
   1308             if (receiverRecords != null) {
   1309                 receiverRecords.remove(this.mProvider);
   1310 
   1311                 // and also remove the Receiver if it has no more update records
   1312                 if (removeReceiver && receiverRecords.size() == 0) {
   1313                     removeUpdatesLocked(mReceiver);
   1314                 }
   1315             }
   1316         }
   1317 
   1318         @Override
   1319         public String toString() {
   1320             StringBuilder s = new StringBuilder();
   1321             s.append("UpdateRecord[");
   1322             s.append(mProvider);
   1323             s.append(' ').append(mReceiver.mPackageName).append('(');
   1324             s.append(mReceiver.mUid).append(')');
   1325             s.append(' ').append(mRequest);
   1326             s.append(']');
   1327             return s.toString();
   1328         }
   1329     }
   1330 
   1331     private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
   1332             String packageName, WorkSource workSource, boolean hideFromAppOps) {
   1333         IBinder binder = listener.asBinder();
   1334         Receiver receiver = mReceivers.get(binder);
   1335         if (receiver == null) {
   1336             receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
   1337                     hideFromAppOps);
   1338             mReceivers.put(binder, receiver);
   1339 
   1340             try {
   1341                 receiver.getListener().asBinder().linkToDeath(receiver, 0);
   1342             } catch (RemoteException e) {
   1343                 Slog.e(TAG, "linkToDeath failed:", e);
   1344                 return null;
   1345             }
   1346         }
   1347         return receiver;
   1348     }
   1349 
   1350     private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
   1351             WorkSource workSource, boolean hideFromAppOps) {
   1352         Receiver receiver = mReceivers.get(intent);
   1353         if (receiver == null) {
   1354             receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
   1355                     hideFromAppOps);
   1356             mReceivers.put(intent, receiver);
   1357         }
   1358         return receiver;
   1359     }
   1360 
   1361     /**
   1362      * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
   1363      * and consistency requirements.
   1364      *
   1365      * @param request the LocationRequest from which to create a sanitized version
   1366      * @return a version of request that meets the given resolution and consistency requirements
   1367      * @hide
   1368      */
   1369     private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
   1370         LocationRequest sanitizedRequest = new LocationRequest(request);
   1371         if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
   1372             switch (sanitizedRequest.getQuality()) {
   1373                 case LocationRequest.ACCURACY_FINE:
   1374                     sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
   1375                     break;
   1376                 case LocationRequest.POWER_HIGH:
   1377                     sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
   1378                     break;
   1379             }
   1380             // throttle
   1381             if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
   1382                 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
   1383             }
   1384             if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
   1385                 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
   1386             }
   1387         }
   1388         // make getFastestInterval() the minimum of interval and fastest interval
   1389         if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
   1390             request.setFastestInterval(request.getInterval());
   1391         }
   1392         return sanitizedRequest;
   1393     }
   1394 
   1395     private void checkPackageName(String packageName) {
   1396         if (packageName == null) {
   1397             throw new SecurityException("invalid package name: " + packageName);
   1398         }
   1399         int uid = Binder.getCallingUid();
   1400         String[] packages = mPackageManager.getPackagesForUid(uid);
   1401         if (packages == null) {
   1402             throw new SecurityException("invalid UID " + uid);
   1403         }
   1404         for (String pkg : packages) {
   1405             if (packageName.equals(pkg)) return;
   1406         }
   1407         throw new SecurityException("invalid package name: " + packageName);
   1408     }
   1409 
   1410     private void checkPendingIntent(PendingIntent intent) {
   1411         if (intent == null) {
   1412             throw new IllegalArgumentException("invalid pending intent: " + intent);
   1413         }
   1414     }
   1415 
   1416     private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
   1417             int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
   1418         if (intent == null && listener == null) {
   1419             throw new IllegalArgumentException("need either listener or intent");
   1420         } else if (intent != null && listener != null) {
   1421             throw new IllegalArgumentException("cannot register both listener and intent");
   1422         } else if (intent != null) {
   1423             checkPendingIntent(intent);
   1424             return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
   1425         } else {
   1426             return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
   1427         }
   1428     }
   1429 
   1430     @Override
   1431     public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
   1432             PendingIntent intent, String packageName) {
   1433         if (request == null) request = DEFAULT_LOCATION_REQUEST;
   1434         checkPackageName(packageName);
   1435         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
   1436         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
   1437                 request.getProvider());
   1438         WorkSource workSource = request.getWorkSource();
   1439         if (workSource != null && workSource.size() > 0) {
   1440             checkDeviceStatsAllowed();
   1441         }
   1442         boolean hideFromAppOps = request.getHideFromAppOps();
   1443         if (hideFromAppOps) {
   1444             checkUpdateAppOpsAllowed();
   1445         }
   1446         LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
   1447 
   1448         final int pid = Binder.getCallingPid();
   1449         final int uid = Binder.getCallingUid();
   1450         // providers may use public location API's, need to clear identity
   1451         long identity = Binder.clearCallingIdentity();
   1452         try {
   1453             // We don't check for MODE_IGNORED here; we will do that when we go to deliver
   1454             // a location.
   1455             checkLocationAccess(uid, packageName, allowedResolutionLevel);
   1456 
   1457             synchronized (mLock) {
   1458                 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
   1459                         packageName, workSource, hideFromAppOps);
   1460                 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
   1461             }
   1462         } finally {
   1463             Binder.restoreCallingIdentity(identity);
   1464         }
   1465     }
   1466 
   1467     private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
   1468             int pid, int uid, String packageName) {
   1469         // Figure out the provider. Either its explicitly request (legacy use cases), or
   1470         // use the fused provider
   1471         if (request == null) request = DEFAULT_LOCATION_REQUEST;
   1472         String name = request.getProvider();
   1473         if (name == null) {
   1474             throw new IllegalArgumentException("provider name must not be null");
   1475         }
   1476 
   1477         if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
   1478                 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
   1479         LocationProviderInterface provider = mProvidersByName.get(name);
   1480         if (provider == null) {
   1481             throw new IllegalArgumentException("provider doesn't exist: " + name);
   1482         }
   1483 
   1484         UpdateRecord record = new UpdateRecord(name, request, receiver);
   1485         UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
   1486         if (oldRecord != null) {
   1487             oldRecord.disposeLocked(false);
   1488         }
   1489 
   1490         boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
   1491         if (isProviderEnabled) {
   1492             applyRequirementsLocked(name);
   1493         } else {
   1494             // Notify the listener that updates are currently disabled
   1495             receiver.callProviderEnabledLocked(name, false);
   1496         }
   1497         // Update the monitoring here just in case multiple location requests were added to the
   1498         // same receiver (this request may be high power and the initial might not have been).
   1499         receiver.updateMonitoring(true);
   1500     }
   1501 
   1502     @Override
   1503     public void removeUpdates(ILocationListener listener, PendingIntent intent,
   1504             String packageName) {
   1505         checkPackageName(packageName);
   1506 
   1507         final int pid = Binder.getCallingPid();
   1508         final int uid = Binder.getCallingUid();
   1509 
   1510         synchronized (mLock) {
   1511             WorkSource workSource = null;
   1512             boolean hideFromAppOps = false;
   1513             Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
   1514                     packageName, workSource, hideFromAppOps);
   1515 
   1516             // providers may use public location API's, need to clear identity
   1517             long identity = Binder.clearCallingIdentity();
   1518             try {
   1519                 removeUpdatesLocked(receiver);
   1520             } finally {
   1521                 Binder.restoreCallingIdentity(identity);
   1522             }
   1523         }
   1524     }
   1525 
   1526     private void removeUpdatesLocked(Receiver receiver) {
   1527         if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
   1528 
   1529         if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
   1530             receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
   1531             synchronized (receiver) {
   1532                 receiver.clearPendingBroadcastsLocked();
   1533             }
   1534         }
   1535 
   1536         receiver.updateMonitoring(false);
   1537 
   1538         // Record which providers were associated with this listener
   1539         HashSet<String> providers = new HashSet<String>();
   1540         HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
   1541         if (oldRecords != null) {
   1542             // Call dispose() on the obsolete update records.
   1543             for (UpdateRecord record : oldRecords.values()) {
   1544                 record.disposeLocked(false);
   1545             }
   1546             // Accumulate providers
   1547             providers.addAll(oldRecords.keySet());
   1548         }
   1549 
   1550         // update provider
   1551         for (String provider : providers) {
   1552             // If provider is already disabled, don't need to do anything
   1553             if (!isAllowedByCurrentUserSettingsLocked(provider)) {
   1554                 continue;
   1555             }
   1556 
   1557             applyRequirementsLocked(provider);
   1558         }
   1559     }
   1560 
   1561     private void applyAllProviderRequirementsLocked() {
   1562         for (LocationProviderInterface p : mProviders) {
   1563             // If provider is already disabled, don't need to do anything
   1564             if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
   1565                 continue;
   1566             }
   1567 
   1568             applyRequirementsLocked(p.getName());
   1569         }
   1570     }
   1571 
   1572     @Override
   1573     public Location getLastLocation(LocationRequest request, String packageName) {
   1574         if (D) Log.d(TAG, "getLastLocation: " + request);
   1575         if (request == null) request = DEFAULT_LOCATION_REQUEST;
   1576         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
   1577         checkPackageName(packageName);
   1578         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
   1579                 request.getProvider());
   1580         // no need to sanitize this request, as only the provider name is used
   1581 
   1582         final int uid = Binder.getCallingUid();
   1583         final long identity = Binder.clearCallingIdentity();
   1584         try {
   1585             if (mBlacklist.isBlacklisted(packageName)) {
   1586                 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
   1587                         packageName);
   1588                 return null;
   1589             }
   1590 
   1591             if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
   1592                 if (D) Log.d(TAG, "not returning last loc for no op app: " +
   1593                         packageName);
   1594                 return null;
   1595             }
   1596 
   1597             synchronized (mLock) {
   1598                 // Figure out the provider. Either its explicitly request (deprecated API's),
   1599                 // or use the fused provider
   1600                 String name = request.getProvider();
   1601                 if (name == null) name = LocationManager.FUSED_PROVIDER;
   1602                 LocationProviderInterface provider = mProvidersByName.get(name);
   1603                 if (provider == null) return null;
   1604 
   1605                 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
   1606 
   1607                 Location location;
   1608                 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
   1609                     // Make sure that an app with coarse permissions can't get frequent location
   1610                     // updates by calling LocationManager.getLastKnownLocation repeatedly.
   1611                     location = mLastLocationCoarseInterval.get(name);
   1612                 } else {
   1613                     location = mLastLocation.get(name);
   1614                 }
   1615                 if (location == null) {
   1616                     return null;
   1617                 }
   1618                 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
   1619                     Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
   1620                     if (noGPSLocation != null) {
   1621                         return new Location(mLocationFudger.getOrCreate(noGPSLocation));
   1622                     }
   1623                 } else {
   1624                     return new Location(location);
   1625                 }
   1626             }
   1627             return null;
   1628         } finally {
   1629             Binder.restoreCallingIdentity(identity);
   1630         }
   1631     }
   1632 
   1633     @Override
   1634     public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
   1635             String packageName) {
   1636         if (request == null) request = DEFAULT_LOCATION_REQUEST;
   1637         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
   1638         checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
   1639         checkPendingIntent(intent);
   1640         checkPackageName(packageName);
   1641         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
   1642                 request.getProvider());
   1643         LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
   1644 
   1645         if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
   1646 
   1647         // geo-fence manager uses the public location API, need to clear identity
   1648         int uid = Binder.getCallingUid();
   1649         if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
   1650             // temporary measure until geofences work for secondary users
   1651             Log.w(TAG, "proximity alerts are currently available only to the primary user");
   1652             return;
   1653         }
   1654         long identity = Binder.clearCallingIdentity();
   1655         try {
   1656             mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
   1657                     uid, packageName);
   1658         } finally {
   1659             Binder.restoreCallingIdentity(identity);
   1660         }
   1661     }
   1662 
   1663     @Override
   1664     public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
   1665         checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
   1666         checkPendingIntent(intent);
   1667         checkPackageName(packageName);
   1668 
   1669         if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
   1670 
   1671         // geo-fence manager uses the public location API, need to clear identity
   1672         long identity = Binder.clearCallingIdentity();
   1673         try {
   1674             mGeofenceManager.removeFence(geofence, intent);
   1675         } finally {
   1676             Binder.restoreCallingIdentity(identity);
   1677         }
   1678     }
   1679 
   1680 
   1681     @Override
   1682     public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
   1683         if (mGpsStatusProvider == null) {
   1684             return false;
   1685         }
   1686         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
   1687         checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
   1688                 LocationManager.GPS_PROVIDER);
   1689 
   1690         final int uid = Binder.getCallingUid();
   1691         final long ident = Binder.clearCallingIdentity();
   1692         try {
   1693             if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
   1694                 return false;
   1695             }
   1696         } finally {
   1697             Binder.restoreCallingIdentity(ident);
   1698         }
   1699 
   1700         try {
   1701             mGpsStatusProvider.addGpsStatusListener(listener);
   1702         } catch (RemoteException e) {
   1703             Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
   1704             return false;
   1705         }
   1706         return true;
   1707     }
   1708 
   1709     @Override
   1710     public void removeGpsStatusListener(IGpsStatusListener listener) {
   1711         synchronized (mLock) {
   1712             try {
   1713                 mGpsStatusProvider.removeGpsStatusListener(listener);
   1714             } catch (Exception e) {
   1715                 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
   1716             }
   1717         }
   1718     }
   1719 
   1720     @Override
   1721     public boolean sendExtraCommand(String provider, String command, Bundle extras) {
   1722         if (provider == null) {
   1723             // throw NullPointerException to remain compatible with previous implementation
   1724             throw new NullPointerException();
   1725         }
   1726         checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
   1727                 provider);
   1728 
   1729         // and check for ACCESS_LOCATION_EXTRA_COMMANDS
   1730         if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
   1731                 != PackageManager.PERMISSION_GRANTED)) {
   1732             throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
   1733         }
   1734 
   1735         synchronized (mLock) {
   1736             LocationProviderInterface p = mProvidersByName.get(provider);
   1737             if (p == null) return false;
   1738 
   1739             return p.sendExtraCommand(command, extras);
   1740         }
   1741     }
   1742 
   1743     @Override
   1744     public boolean sendNiResponse(int notifId, int userResponse) {
   1745         if (Binder.getCallingUid() != Process.myUid()) {
   1746             throw new SecurityException(
   1747                     "calling sendNiResponse from outside of the system is not allowed");
   1748         }
   1749         try {
   1750             return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
   1751         } catch (RemoteException e) {
   1752             Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
   1753             return false;
   1754         }
   1755     }
   1756 
   1757     /**
   1758      * @return null if the provider does not exist
   1759      * @throws SecurityException if the provider is not allowed to be
   1760      * accessed by the caller
   1761      */
   1762     @Override
   1763     public ProviderProperties getProviderProperties(String provider) {
   1764         if (mProvidersByName.get(provider) == null) {
   1765           return null;
   1766         }
   1767 
   1768         checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
   1769                 provider);
   1770 
   1771         LocationProviderInterface p;
   1772         synchronized (mLock) {
   1773             p = mProvidersByName.get(provider);
   1774         }
   1775 
   1776         if (p == null) return null;
   1777         return p.getProperties();
   1778     }
   1779 
   1780     @Override
   1781     public boolean isProviderEnabled(String provider) {
   1782         // TODO: remove this check in next release, see b/10696351
   1783         checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
   1784                 provider);
   1785 
   1786         // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
   1787         // so we discourage its use
   1788         if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
   1789 
   1790         int uid = Binder.getCallingUid();
   1791         long identity = Binder.clearCallingIdentity();
   1792         try {
   1793             synchronized (mLock) {
   1794                 LocationProviderInterface p = mProvidersByName.get(provider);
   1795                 if (p == null) return false;
   1796 
   1797                 return isAllowedByUserSettingsLocked(provider, uid);
   1798             }
   1799         } finally {
   1800             Binder.restoreCallingIdentity(identity);
   1801         }
   1802     }
   1803 
   1804     /**
   1805      * Returns "true" if the UID belongs to a bound location provider.
   1806      *
   1807      * @param uid the uid
   1808      * @return true if uid belongs to a bound location provider
   1809      */
   1810     private boolean isUidALocationProvider(int uid) {
   1811         if (uid == Process.SYSTEM_UID) {
   1812             return true;
   1813         }
   1814         if (mGeocodeProvider != null) {
   1815             if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
   1816         }
   1817         for (LocationProviderProxy proxy : mProxyProviders) {
   1818             if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
   1819         }
   1820         return false;
   1821     }
   1822 
   1823     private void checkCallerIsProvider() {
   1824         if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
   1825                 == PackageManager.PERMISSION_GRANTED) {
   1826             return;
   1827         }
   1828 
   1829         // Previously we only used the INSTALL_LOCATION_PROVIDER
   1830         // check. But that is system or signature
   1831         // protection level which is not flexible enough for
   1832         // providers installed oustide the system image. So
   1833         // also allow providers with a UID matching the
   1834         // currently bound package name
   1835 
   1836         if (isUidALocationProvider(Binder.getCallingUid())) {
   1837             return;
   1838         }
   1839 
   1840         throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
   1841                 "or UID of a currently bound location provider");
   1842     }
   1843 
   1844     private boolean doesPackageHaveUid(int uid, String packageName) {
   1845         if (packageName == null) {
   1846             return false;
   1847         }
   1848         try {
   1849             ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
   1850             if (appInfo.uid != uid) {
   1851                 return false;
   1852             }
   1853         } catch (NameNotFoundException e) {
   1854             return false;
   1855         }
   1856         return true;
   1857     }
   1858 
   1859     @Override
   1860     public void reportLocation(Location location, boolean passive) {
   1861         checkCallerIsProvider();
   1862 
   1863         if (!location.isComplete()) {
   1864             Log.w(TAG, "Dropping incomplete location: " + location);
   1865             return;
   1866         }
   1867 
   1868         mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
   1869         Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
   1870         m.arg1 = (passive ? 1 : 0);
   1871         mLocationHandler.sendMessageAtFrontOfQueue(m);
   1872     }
   1873 
   1874 
   1875     private static boolean shouldBroadcastSafe(
   1876             Location loc, Location lastLoc, UpdateRecord record, long now) {
   1877         // Always broadcast the first update
   1878         if (lastLoc == null) {
   1879             return true;
   1880         }
   1881 
   1882         // Check whether sufficient time has passed
   1883         long minTime = record.mRequest.getFastestInterval();
   1884         long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
   1885                 / NANOS_PER_MILLI;
   1886         if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
   1887             return false;
   1888         }
   1889 
   1890         // Check whether sufficient distance has been traveled
   1891         double minDistance = record.mRequest.getSmallestDisplacement();
   1892         if (minDistance > 0.0) {
   1893             if (loc.distanceTo(lastLoc) <= minDistance) {
   1894                 return false;
   1895             }
   1896         }
   1897 
   1898         // Check whether sufficient number of udpates is left
   1899         if (record.mRequest.getNumUpdates() <= 0) {
   1900             return false;
   1901         }
   1902 
   1903         // Check whether the expiry date has passed
   1904         if (record.mRequest.getExpireAt() < now) {
   1905             return false;
   1906         }
   1907 
   1908         return true;
   1909     }
   1910 
   1911     private void handleLocationChangedLocked(Location location, boolean passive) {
   1912         if (D) Log.d(TAG, "incoming location: " + location);
   1913 
   1914         long now = SystemClock.elapsedRealtime();
   1915         String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
   1916 
   1917         // Skip if the provider is unknown.
   1918         LocationProviderInterface p = mProvidersByName.get(provider);
   1919         if (p == null) return;
   1920 
   1921         // Update last known locations
   1922         Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
   1923         Location lastNoGPSLocation = null;
   1924         Location lastLocation = mLastLocation.get(provider);
   1925         if (lastLocation == null) {
   1926             lastLocation = new Location(provider);
   1927             mLastLocation.put(provider, lastLocation);
   1928         } else {
   1929             lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
   1930             if (noGPSLocation == null && lastNoGPSLocation != null) {
   1931                 // New location has no no-GPS location: adopt last no-GPS location. This is set
   1932                 // directly into location because we do not want to notify COARSE clients.
   1933                 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
   1934             }
   1935         }
   1936         lastLocation.set(location);
   1937 
   1938         // Update last known coarse interval location if enough time has passed.
   1939         Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
   1940         if (lastLocationCoarseInterval == null) {
   1941             lastLocationCoarseInterval = new Location(location);
   1942             mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
   1943         }
   1944         long timeDiffNanos = location.getElapsedRealtimeNanos()
   1945                 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
   1946         if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
   1947             lastLocationCoarseInterval.set(location);
   1948         }
   1949         // Don't ever return a coarse location that is more recent than the allowed update
   1950         // interval (i.e. don't allow an app to keep registering and unregistering for
   1951         // location updates to overcome the minimum interval).
   1952         noGPSLocation =
   1953                 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
   1954 
   1955         // Skip if there are no UpdateRecords for this provider.
   1956         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
   1957         if (records == null || records.size() == 0) return;
   1958 
   1959         // Fetch coarse location
   1960         Location coarseLocation = null;
   1961         if (noGPSLocation != null) {
   1962             coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
   1963         }
   1964 
   1965         // Fetch latest status update time
   1966         long newStatusUpdateTime = p.getStatusUpdateTime();
   1967 
   1968        // Get latest status
   1969         Bundle extras = new Bundle();
   1970         int status = p.getStatus(extras);
   1971 
   1972         ArrayList<Receiver> deadReceivers = null;
   1973         ArrayList<UpdateRecord> deadUpdateRecords = null;
   1974 
   1975         // Broadcast location or status to all listeners
   1976         for (UpdateRecord r : records) {
   1977             Receiver receiver = r.mReceiver;
   1978             boolean receiverDead = false;
   1979 
   1980             int receiverUserId = UserHandle.getUserId(receiver.mUid);
   1981             if (receiverUserId != mCurrentUserId && !isUidALocationProvider(receiver.mUid)) {
   1982                 if (D) {
   1983                     Log.d(TAG, "skipping loc update for background user " + receiverUserId +
   1984                             " (current user: " + mCurrentUserId + ", app: " +
   1985                             receiver.mPackageName + ")");
   1986                 }
   1987                 continue;
   1988             }
   1989 
   1990             if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
   1991                 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
   1992                         receiver.mPackageName);
   1993                 continue;
   1994             }
   1995 
   1996             if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
   1997                     receiver.mAllowedResolutionLevel)) {
   1998                 if (D) Log.d(TAG, "skipping loc update for no op app: " +
   1999                         receiver.mPackageName);
   2000                 continue;
   2001             }
   2002 
   2003             Location notifyLocation = null;
   2004             if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
   2005                 notifyLocation = coarseLocation;  // use coarse location
   2006             } else {
   2007                 notifyLocation = lastLocation;  // use fine location
   2008             }
   2009             if (notifyLocation != null) {
   2010                 Location lastLoc = r.mLastFixBroadcast;
   2011                 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
   2012                     if (lastLoc == null) {
   2013                         lastLoc = new Location(notifyLocation);
   2014                         r.mLastFixBroadcast = lastLoc;
   2015                     } else {
   2016                         lastLoc.set(notifyLocation);
   2017                     }
   2018                     if (!receiver.callLocationChangedLocked(notifyLocation)) {
   2019                         Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
   2020                         receiverDead = true;
   2021                     }
   2022                     r.mRequest.decrementNumUpdates();
   2023                 }
   2024             }
   2025 
   2026             long prevStatusUpdateTime = r.mLastStatusBroadcast;
   2027             if ((newStatusUpdateTime > prevStatusUpdateTime) &&
   2028                     (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
   2029 
   2030                 r.mLastStatusBroadcast = newStatusUpdateTime;
   2031                 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
   2032                     receiverDead = true;
   2033                     Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
   2034                 }
   2035             }
   2036 
   2037             // track expired records
   2038             if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
   2039                 if (deadUpdateRecords == null) {
   2040                     deadUpdateRecords = new ArrayList<UpdateRecord>();
   2041                 }
   2042                 deadUpdateRecords.add(r);
   2043             }
   2044             // track dead receivers
   2045             if (receiverDead) {
   2046                 if (deadReceivers == null) {
   2047                     deadReceivers = new ArrayList<Receiver>();
   2048                 }
   2049                 if (!deadReceivers.contains(receiver)) {
   2050                     deadReceivers.add(receiver);
   2051                 }
   2052             }
   2053         }
   2054 
   2055         // remove dead records and receivers outside the loop
   2056         if (deadReceivers != null) {
   2057             for (Receiver receiver : deadReceivers) {
   2058                 removeUpdatesLocked(receiver);
   2059             }
   2060         }
   2061         if (deadUpdateRecords != null) {
   2062             for (UpdateRecord r : deadUpdateRecords) {
   2063                 r.disposeLocked(true);
   2064             }
   2065             applyRequirementsLocked(provider);
   2066         }
   2067     }
   2068 
   2069     private class LocationWorkerHandler extends Handler {
   2070         public LocationWorkerHandler(Looper looper) {
   2071             super(looper, null, true);
   2072         }
   2073 
   2074         @Override
   2075         public void handleMessage(Message msg) {
   2076             switch (msg.what) {
   2077                 case MSG_LOCATION_CHANGED:
   2078                     handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
   2079                     break;
   2080             }
   2081         }
   2082     }
   2083 
   2084     private boolean isMockProvider(String provider) {
   2085         synchronized (mLock) {
   2086             return mMockProviders.containsKey(provider);
   2087         }
   2088     }
   2089 
   2090     private void handleLocationChanged(Location location, boolean passive) {
   2091         // create a working copy of the incoming Location so that the service can modify it without
   2092         // disturbing the caller's copy
   2093         Location myLocation = new Location(location);
   2094         String provider = myLocation.getProvider();
   2095 
   2096         // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
   2097         // bit if location did not come from a mock provider because passive/fused providers can
   2098         // forward locations from mock providers, and should not grant them legitimacy in doing so.
   2099         if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
   2100             myLocation.setIsFromMockProvider(true);
   2101         }
   2102 
   2103         synchronized (mLock) {
   2104             if (isAllowedByCurrentUserSettingsLocked(provider)) {
   2105                 if (!passive) {
   2106                     // notify passive provider of the new location
   2107                     mPassiveProvider.updateLocation(myLocation);
   2108                 }
   2109                 handleLocationChangedLocked(myLocation, passive);
   2110             }
   2111         }
   2112     }
   2113 
   2114     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
   2115         @Override
   2116         public void onPackageDisappeared(String packageName, int reason) {
   2117             // remove all receivers associated with this package name
   2118             synchronized (mLock) {
   2119                 ArrayList<Receiver> deadReceivers = null;
   2120 
   2121                 for (Receiver receiver : mReceivers.values()) {
   2122                     if (receiver.mPackageName.equals(packageName)) {
   2123                         if (deadReceivers == null) {
   2124                             deadReceivers = new ArrayList<Receiver>();
   2125                         }
   2126                         deadReceivers.add(receiver);
   2127                     }
   2128                 }
   2129 
   2130                 // perform removal outside of mReceivers loop
   2131                 if (deadReceivers != null) {
   2132                     for (Receiver receiver : deadReceivers) {
   2133                         removeUpdatesLocked(receiver);
   2134                     }
   2135                 }
   2136             }
   2137         }
   2138     };
   2139 
   2140     // Geocoder
   2141 
   2142     @Override
   2143     public boolean geocoderIsPresent() {
   2144         return mGeocodeProvider != null;
   2145     }
   2146 
   2147     @Override
   2148     public String getFromLocation(double latitude, double longitude, int maxResults,
   2149             GeocoderParams params, List<Address> addrs) {
   2150         if (mGeocodeProvider != null) {
   2151             return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
   2152                     params, addrs);
   2153         }
   2154         return null;
   2155     }
   2156 
   2157 
   2158     @Override
   2159     public String getFromLocationName(String locationName,
   2160             double lowerLeftLatitude, double lowerLeftLongitude,
   2161             double upperRightLatitude, double upperRightLongitude, int maxResults,
   2162             GeocoderParams params, List<Address> addrs) {
   2163 
   2164         if (mGeocodeProvider != null) {
   2165             return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
   2166                     lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
   2167                     maxResults, params, addrs);
   2168         }
   2169         return null;
   2170     }
   2171 
   2172     // Mock Providers
   2173 
   2174     private void checkMockPermissionsSafe() {
   2175         boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
   2176                 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
   2177         if (!allowMocks) {
   2178             throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
   2179         }
   2180 
   2181         if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
   2182             PackageManager.PERMISSION_GRANTED) {
   2183             throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
   2184         }
   2185     }
   2186 
   2187     @Override
   2188     public void addTestProvider(String name, ProviderProperties properties) {
   2189         checkMockPermissionsSafe();
   2190 
   2191         if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
   2192             throw new IllegalArgumentException("Cannot mock the passive location provider");
   2193         }
   2194 
   2195         long identity = Binder.clearCallingIdentity();
   2196         synchronized (mLock) {
   2197             MockProvider provider = new MockProvider(name, this, properties);
   2198             // remove the real provider if we are replacing GPS or network provider
   2199             if (LocationManager.GPS_PROVIDER.equals(name)
   2200                     || LocationManager.NETWORK_PROVIDER.equals(name)
   2201                     || LocationManager.FUSED_PROVIDER.equals(name)) {
   2202                 LocationProviderInterface p = mProvidersByName.get(name);
   2203                 if (p != null) {
   2204                     removeProviderLocked(p);
   2205                 }
   2206             }
   2207             if (mProvidersByName.get(name) != null) {
   2208                 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
   2209             }
   2210             addProviderLocked(provider);
   2211             mMockProviders.put(name, provider);
   2212             mLastLocation.put(name, null);
   2213             mLastLocationCoarseInterval.put(name, null);
   2214             updateProvidersLocked();
   2215         }
   2216         Binder.restoreCallingIdentity(identity);
   2217     }
   2218 
   2219     @Override
   2220     public void removeTestProvider(String provider) {
   2221         checkMockPermissionsSafe();
   2222         synchronized (mLock) {
   2223             MockProvider mockProvider = mMockProviders.remove(provider);
   2224             if (mockProvider == null) {
   2225                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2226             }
   2227             long identity = Binder.clearCallingIdentity();
   2228             removeProviderLocked(mProvidersByName.get(provider));
   2229 
   2230             // reinstate real provider if available
   2231             LocationProviderInterface realProvider = mRealProviders.get(provider);
   2232             if (realProvider != null) {
   2233                 addProviderLocked(realProvider);
   2234             }
   2235             mLastLocation.put(provider, null);
   2236             mLastLocationCoarseInterval.put(provider, null);
   2237             updateProvidersLocked();
   2238             Binder.restoreCallingIdentity(identity);
   2239         }
   2240     }
   2241 
   2242     @Override
   2243     public void setTestProviderLocation(String provider, Location loc) {
   2244         checkMockPermissionsSafe();
   2245         synchronized (mLock) {
   2246             MockProvider mockProvider = mMockProviders.get(provider);
   2247             if (mockProvider == null) {
   2248                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2249             }
   2250             // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
   2251             long identity = Binder.clearCallingIdentity();
   2252             mockProvider.setLocation(loc);
   2253             Binder.restoreCallingIdentity(identity);
   2254         }
   2255     }
   2256 
   2257     @Override
   2258     public void clearTestProviderLocation(String provider) {
   2259         checkMockPermissionsSafe();
   2260         synchronized (mLock) {
   2261             MockProvider mockProvider = mMockProviders.get(provider);
   2262             if (mockProvider == null) {
   2263                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2264             }
   2265             mockProvider.clearLocation();
   2266         }
   2267     }
   2268 
   2269     @Override
   2270     public void setTestProviderEnabled(String provider, boolean enabled) {
   2271         checkMockPermissionsSafe();
   2272         synchronized (mLock) {
   2273             MockProvider mockProvider = mMockProviders.get(provider);
   2274             if (mockProvider == null) {
   2275                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2276             }
   2277             long identity = Binder.clearCallingIdentity();
   2278             if (enabled) {
   2279                 mockProvider.enable();
   2280                 mEnabledProviders.add(provider);
   2281                 mDisabledProviders.remove(provider);
   2282             } else {
   2283                 mockProvider.disable();
   2284                 mEnabledProviders.remove(provider);
   2285                 mDisabledProviders.add(provider);
   2286             }
   2287             updateProvidersLocked();
   2288             Binder.restoreCallingIdentity(identity);
   2289         }
   2290     }
   2291 
   2292     @Override
   2293     public void clearTestProviderEnabled(String provider) {
   2294         checkMockPermissionsSafe();
   2295         synchronized (mLock) {
   2296             MockProvider mockProvider = mMockProviders.get(provider);
   2297             if (mockProvider == null) {
   2298                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2299             }
   2300             long identity = Binder.clearCallingIdentity();
   2301             mEnabledProviders.remove(provider);
   2302             mDisabledProviders.remove(provider);
   2303             updateProvidersLocked();
   2304             Binder.restoreCallingIdentity(identity);
   2305         }
   2306     }
   2307 
   2308     @Override
   2309     public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
   2310         checkMockPermissionsSafe();
   2311         synchronized (mLock) {
   2312             MockProvider mockProvider = mMockProviders.get(provider);
   2313             if (mockProvider == null) {
   2314                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2315             }
   2316             mockProvider.setStatus(status, extras, updateTime);
   2317         }
   2318     }
   2319 
   2320     @Override
   2321     public void clearTestProviderStatus(String provider) {
   2322         checkMockPermissionsSafe();
   2323         synchronized (mLock) {
   2324             MockProvider mockProvider = mMockProviders.get(provider);
   2325             if (mockProvider == null) {
   2326                 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
   2327             }
   2328             mockProvider.clearStatus();
   2329         }
   2330     }
   2331 
   2332     private void log(String log) {
   2333         if (Log.isLoggable(TAG, Log.VERBOSE)) {
   2334             Slog.d(TAG, log);
   2335         }
   2336     }
   2337 
   2338     @Override
   2339     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2340         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
   2341                 != PackageManager.PERMISSION_GRANTED) {
   2342             pw.println("Permission Denial: can't dump LocationManagerService from from pid="
   2343                     + Binder.getCallingPid()
   2344                     + ", uid=" + Binder.getCallingUid());
   2345             return;
   2346         }
   2347 
   2348         synchronized (mLock) {
   2349             pw.println("Current Location Manager state:");
   2350             pw.println("  Location Listeners:");
   2351             for (Receiver receiver : mReceivers.values()) {
   2352                 pw.println("    " + receiver);
   2353             }
   2354             pw.println("  Records by Provider:");
   2355             for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
   2356                 pw.println("    " + entry.getKey() + ":");
   2357                 for (UpdateRecord record : entry.getValue()) {
   2358                     pw.println("      " + record);
   2359                 }
   2360             }
   2361             pw.println("  Last Known Locations:");
   2362             for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
   2363                 String provider = entry.getKey();
   2364                 Location location = entry.getValue();
   2365                 pw.println("    " + provider + ": " + location);
   2366             }
   2367 
   2368             pw.println("  Last Known Locations Coarse Intervals:");
   2369             for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
   2370                 String provider = entry.getKey();
   2371                 Location location = entry.getValue();
   2372                 pw.println("    " + provider + ": " + location);
   2373             }
   2374 
   2375             mGeofenceManager.dump(pw);
   2376 
   2377             if (mEnabledProviders.size() > 0) {
   2378                 pw.println("  Enabled Providers:");
   2379                 for (String i : mEnabledProviders) {
   2380                     pw.println("    " + i);
   2381                 }
   2382 
   2383             }
   2384             if (mDisabledProviders.size() > 0) {
   2385                 pw.println("  Disabled Providers:");
   2386                 for (String i : mDisabledProviders) {
   2387                     pw.println("    " + i);
   2388                 }
   2389             }
   2390             pw.append("  ");
   2391             mBlacklist.dump(pw);
   2392             if (mMockProviders.size() > 0) {
   2393                 pw.println("  Mock Providers:");
   2394                 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
   2395                     i.getValue().dump(pw, "      ");
   2396                 }
   2397             }
   2398 
   2399             pw.append("  fudger: ");
   2400             mLocationFudger.dump(fd, pw,  args);
   2401 
   2402             if (args.length > 0 && "short".equals(args[0])) {
   2403                 return;
   2404             }
   2405             for (LocationProviderInterface provider: mProviders) {
   2406                 pw.print(provider.getName() + " Internal State");
   2407                 if (provider instanceof LocationProviderProxy) {
   2408                     LocationProviderProxy proxy = (LocationProviderProxy) provider;
   2409                     pw.print(" (" + proxy.getConnectedPackageName() + ")");
   2410                 }
   2411                 pw.println(":");
   2412                 provider.dump(fd, pw, args);
   2413             }
   2414         }
   2415     }
   2416 }
   2417