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