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