OSDN Git Service

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