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