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