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