OSDN Git Service

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