LocationManagerService.java revision 8e4799ad456c972cc340d3f484afd69b2f14a761
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    @Override
1962    public boolean isProviderEnabled(String provider) {
1963        // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
1964        // so we discourage its use
1965        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1966
1967        int uid = Binder.getCallingUid();
1968        long identity = Binder.clearCallingIdentity();
1969        try {
1970            synchronized (mLock) {
1971                LocationProviderInterface p = mProvidersByName.get(provider);
1972                if (p == null) return false;
1973
1974                return isAllowedByUserSettingsLocked(provider, uid);
1975            }
1976        } finally {
1977            Binder.restoreCallingIdentity(identity);
1978        }
1979    }
1980
1981    /**
1982     * Returns "true" if the UID belongs to a bound location provider.
1983     *
1984     * @param uid the uid
1985     * @return true if uid belongs to a bound location provider
1986     */
1987    private boolean isUidALocationProvider(int uid) {
1988        if (uid == Process.SYSTEM_UID) {
1989            return true;
1990        }
1991        if (mGeocodeProvider != null) {
1992            if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1993        }
1994        for (LocationProviderProxy proxy : mProxyProviders) {
1995            if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
1996        }
1997        return false;
1998    }
1999
2000    private void checkCallerIsProvider() {
2001        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2002                == PackageManager.PERMISSION_GRANTED) {
2003            return;
2004        }
2005
2006        // Previously we only used the INSTALL_LOCATION_PROVIDER
2007        // check. But that is system or signature
2008        // protection level which is not flexible enough for
2009        // providers installed oustide the system image. So
2010        // also allow providers with a UID matching the
2011        // currently bound package name
2012
2013        if (isUidALocationProvider(Binder.getCallingUid())) {
2014            return;
2015        }
2016
2017        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2018                "or UID of a currently bound location provider");
2019    }
2020
2021    /**
2022     * Returns true if the given package belongs to the given uid.
2023     */
2024    private boolean doesUidHavePackage(int uid, String packageName) {
2025        if (packageName == null) {
2026            return false;
2027        }
2028        String[] packageNames = mPackageManager.getPackagesForUid(uid);
2029        if (packageNames == null) {
2030            return false;
2031        }
2032        for (String name : packageNames) {
2033            if (packageName.equals(name)) {
2034                return true;
2035            }
2036        }
2037        return false;
2038    }
2039
2040    @Override
2041    public void reportLocation(Location location, boolean passive) {
2042        checkCallerIsProvider();
2043
2044        if (!location.isComplete()) {
2045            Log.w(TAG, "Dropping incomplete location: " + location);
2046            return;
2047        }
2048
2049        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2050        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
2051        m.arg1 = (passive ? 1 : 0);
2052        mLocationHandler.sendMessageAtFrontOfQueue(m);
2053    }
2054
2055
2056    private static boolean shouldBroadcastSafe(
2057            Location loc, Location lastLoc, UpdateRecord record, long now) {
2058        // Always broadcast the first update
2059        if (lastLoc == null) {
2060            return true;
2061        }
2062
2063        // Check whether sufficient time has passed
2064        long minTime = record.mRequest.getFastestInterval();
2065        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2066                / NANOS_PER_MILLI;
2067        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
2068            return false;
2069        }
2070
2071        // Check whether sufficient distance has been traveled
2072        double minDistance = record.mRequest.getSmallestDisplacement();
2073        if (minDistance > 0.0) {
2074            if (loc.distanceTo(lastLoc) <= minDistance) {
2075                return false;
2076            }
2077        }
2078
2079        // Check whether sufficient number of udpates is left
2080        if (record.mRequest.getNumUpdates() <= 0) {
2081            return false;
2082        }
2083
2084        // Check whether the expiry date has passed
2085        if (record.mRequest.getExpireAt() < now) {
2086            return false;
2087        }
2088
2089        return true;
2090    }
2091
2092    private void handleLocationChangedLocked(Location location, boolean passive) {
2093        if (D) Log.d(TAG, "incoming location: " + location);
2094
2095        long now = SystemClock.elapsedRealtime();
2096        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
2097
2098        // Skip if the provider is unknown.
2099        LocationProviderInterface p = mProvidersByName.get(provider);
2100        if (p == null) return;
2101
2102        // Update last known locations
2103        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2104        Location lastNoGPSLocation = null;
2105        Location lastLocation = mLastLocation.get(provider);
2106        if (lastLocation == null) {
2107            lastLocation = new Location(provider);
2108            mLastLocation.put(provider, lastLocation);
2109        } else {
2110            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2111            if (noGPSLocation == null && lastNoGPSLocation != null) {
2112                // New location has no no-GPS location: adopt last no-GPS location. This is set
2113                // directly into location because we do not want to notify COARSE clients.
2114                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2115            }
2116        }
2117        lastLocation.set(location);
2118
2119        // Update last known coarse interval location if enough time has passed.
2120        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2121        if (lastLocationCoarseInterval == null) {
2122            lastLocationCoarseInterval = new Location(location);
2123            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2124        }
2125        long timeDiffNanos = location.getElapsedRealtimeNanos()
2126                - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2127        if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2128            lastLocationCoarseInterval.set(location);
2129        }
2130        // Don't ever return a coarse location that is more recent than the allowed update
2131        // interval (i.e. don't allow an app to keep registering and unregistering for
2132        // location updates to overcome the minimum interval).
2133        noGPSLocation =
2134                lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2135
2136        // Skip if there are no UpdateRecords for this provider.
2137        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2138        if (records == null || records.size() == 0) return;
2139
2140        // Fetch coarse location
2141        Location coarseLocation = null;
2142        if (noGPSLocation != null) {
2143            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2144        }
2145
2146        // Fetch latest status update time
2147        long newStatusUpdateTime = p.getStatusUpdateTime();
2148
2149        // Get latest status
2150        Bundle extras = new Bundle();
2151        int status = p.getStatus(extras);
2152
2153        ArrayList<Receiver> deadReceivers = null;
2154        ArrayList<UpdateRecord> deadUpdateRecords = null;
2155
2156        // Broadcast location or status to all listeners
2157        for (UpdateRecord r : records) {
2158            Receiver receiver = r.mReceiver;
2159            boolean receiverDead = false;
2160
2161            int receiverUserId = UserHandle.getUserId(receiver.mUid);
2162            if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
2163                if (D) {
2164                    Log.d(TAG, "skipping loc update for background user " + receiverUserId +
2165                            " (current user: " + mCurrentUserId + ", app: " +
2166                            receiver.mPackageName + ")");
2167                }
2168                continue;
2169            }
2170
2171            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2172                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2173                        receiver.mPackageName);
2174                continue;
2175            }
2176
2177            if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
2178                    receiver.mAllowedResolutionLevel)) {
2179                if (D) Log.d(TAG, "skipping loc update for no op app: " +
2180                        receiver.mPackageName);
2181                continue;
2182            }
2183
2184            Location notifyLocation = null;
2185            if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2186                notifyLocation = coarseLocation;  // use coarse location
2187            } else {
2188                notifyLocation = lastLocation;  // use fine location
2189            }
2190            if (notifyLocation != null) {
2191                Location lastLoc = r.mLastFixBroadcast;
2192                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
2193                    if (lastLoc == null) {
2194                        lastLoc = new Location(notifyLocation);
2195                        r.mLastFixBroadcast = lastLoc;
2196                    } else {
2197                        lastLoc.set(notifyLocation);
2198                    }
2199                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
2200                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2201                        receiverDead = true;
2202                    }
2203                    r.mRequest.decrementNumUpdates();
2204                }
2205            }
2206
2207            long prevStatusUpdateTime = r.mLastStatusBroadcast;
2208            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
2209                    (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
2210
2211                r.mLastStatusBroadcast = newStatusUpdateTime;
2212                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
2213                    receiverDead = true;
2214                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
2215                }
2216            }
2217
2218            // track expired records
2219            if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
2220                if (deadUpdateRecords == null) {
2221                    deadUpdateRecords = new ArrayList<UpdateRecord>();
2222                }
2223                deadUpdateRecords.add(r);
2224            }
2225            // track dead receivers
2226            if (receiverDead) {
2227                if (deadReceivers == null) {
2228                    deadReceivers = new ArrayList<Receiver>();
2229                }
2230                if (!deadReceivers.contains(receiver)) {
2231                    deadReceivers.add(receiver);
2232                }
2233            }
2234        }
2235
2236        // remove dead records and receivers outside the loop
2237        if (deadReceivers != null) {
2238            for (Receiver receiver : deadReceivers) {
2239                removeUpdatesLocked(receiver);
2240            }
2241        }
2242        if (deadUpdateRecords != null) {
2243            for (UpdateRecord r : deadUpdateRecords) {
2244                r.disposeLocked(true);
2245            }
2246            applyRequirementsLocked(provider);
2247        }
2248    }
2249
2250    private class LocationWorkerHandler extends Handler {
2251        public LocationWorkerHandler(Looper looper) {
2252            super(looper, null, true);
2253        }
2254
2255        @Override
2256        public void handleMessage(Message msg) {
2257            switch (msg.what) {
2258                case MSG_LOCATION_CHANGED:
2259                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2260                    break;
2261            }
2262        }
2263    }
2264
2265    private boolean isMockProvider(String provider) {
2266        synchronized (mLock) {
2267            return mMockProviders.containsKey(provider);
2268        }
2269    }
2270
2271    private void handleLocationChanged(Location location, boolean passive) {
2272        // create a working copy of the incoming Location so that the service can modify it without
2273        // disturbing the caller's copy
2274        Location myLocation = new Location(location);
2275        String provider = myLocation.getProvider();
2276
2277        // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2278        // bit if location did not come from a mock provider because passive/fused providers can
2279        // forward locations from mock providers, and should not grant them legitimacy in doing so.
2280        if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2281            myLocation.setIsFromMockProvider(true);
2282        }
2283
2284        synchronized (mLock) {
2285            if (isAllowedByCurrentUserSettingsLocked(provider)) {
2286                if (!passive) {
2287                    // notify passive provider of the new location
2288                    mPassiveProvider.updateLocation(myLocation);
2289                }
2290                handleLocationChangedLocked(myLocation, passive);
2291            }
2292        }
2293    }
2294
2295    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2296        @Override
2297        public void onPackageDisappeared(String packageName, int reason) {
2298            // remove all receivers associated with this package name
2299            synchronized (mLock) {
2300                ArrayList<Receiver> deadReceivers = null;
2301
2302                for (Receiver receiver : mReceivers.values()) {
2303                    if (receiver.mPackageName.equals(packageName)) {
2304                        if (deadReceivers == null) {
2305                            deadReceivers = new ArrayList<Receiver>();
2306                        }
2307                        deadReceivers.add(receiver);
2308                    }
2309                }
2310
2311                // perform removal outside of mReceivers loop
2312                if (deadReceivers != null) {
2313                    for (Receiver receiver : deadReceivers) {
2314                        removeUpdatesLocked(receiver);
2315                    }
2316                }
2317            }
2318        }
2319    };
2320
2321    // Geocoder
2322
2323    @Override
2324    public boolean geocoderIsPresent() {
2325        return mGeocodeProvider != null;
2326    }
2327
2328    @Override
2329    public String getFromLocation(double latitude, double longitude, int maxResults,
2330            GeocoderParams params, List<Address> addrs) {
2331        if (mGeocodeProvider != null) {
2332            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2333                    params, addrs);
2334        }
2335        return null;
2336    }
2337
2338
2339    @Override
2340    public String getFromLocationName(String locationName,
2341            double lowerLeftLatitude, double lowerLeftLongitude,
2342            double upperRightLatitude, double upperRightLongitude, int maxResults,
2343            GeocoderParams params, List<Address> addrs) {
2344
2345        if (mGeocodeProvider != null) {
2346            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2347                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2348                    maxResults, params, addrs);
2349        }
2350        return null;
2351    }
2352
2353    // Mock Providers
2354
2355    private void checkMockPermissionsSafe() {
2356        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2357                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2358        if (!allowMocks) {
2359            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2360        }
2361
2362        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2363                PackageManager.PERMISSION_GRANTED) {
2364            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
2365        }
2366    }
2367
2368    @Override
2369    public void addTestProvider(String name, ProviderProperties properties) {
2370        checkMockPermissionsSafe();
2371
2372        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2373            throw new IllegalArgumentException("Cannot mock the passive location provider");
2374        }
2375
2376        long identity = Binder.clearCallingIdentity();
2377        synchronized (mLock) {
2378            // remove the real provider if we are replacing GPS or network provider
2379            if (LocationManager.GPS_PROVIDER.equals(name)
2380                    || LocationManager.NETWORK_PROVIDER.equals(name)
2381                    || LocationManager.FUSED_PROVIDER.equals(name)) {
2382                LocationProviderInterface p = mProvidersByName.get(name);
2383                if (p != null) {
2384                    removeProviderLocked(p);
2385                }
2386            }
2387            addTestProviderLocked(name, properties);
2388            updateProvidersLocked();
2389        }
2390        Binder.restoreCallingIdentity(identity);
2391    }
2392
2393    private void addTestProviderLocked(String name, ProviderProperties properties) {
2394        if (mProvidersByName.get(name) != null) {
2395            throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2396        }
2397        MockProvider provider = new MockProvider(name, this, properties);
2398        addProviderLocked(provider);
2399        mMockProviders.put(name, provider);
2400        mLastLocation.put(name, null);
2401        mLastLocationCoarseInterval.put(name, null);
2402    }
2403
2404    @Override
2405    public void removeTestProvider(String provider) {
2406        checkMockPermissionsSafe();
2407        synchronized (mLock) {
2408
2409            // These methods can't be called after removing the test provider, so first make sure
2410            // we don't leave anything dangling.
2411            clearTestProviderEnabled(provider);
2412            clearTestProviderLocation(provider);
2413            clearTestProviderStatus(provider);
2414
2415            MockProvider mockProvider = mMockProviders.remove(provider);
2416            if (mockProvider == null) {
2417                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2418            }
2419            long identity = Binder.clearCallingIdentity();
2420            removeProviderLocked(mProvidersByName.get(provider));
2421
2422            // reinstate real provider if available
2423            LocationProviderInterface realProvider = mRealProviders.get(provider);
2424            if (realProvider != null) {
2425                addProviderLocked(realProvider);
2426            }
2427            mLastLocation.put(provider, null);
2428            mLastLocationCoarseInterval.put(provider, null);
2429            updateProvidersLocked();
2430            Binder.restoreCallingIdentity(identity);
2431        }
2432    }
2433
2434    @Override
2435    public void setTestProviderLocation(String provider, Location loc) {
2436        checkMockPermissionsSafe();
2437        synchronized (mLock) {
2438            MockProvider mockProvider = mMockProviders.get(provider);
2439            if (mockProvider == null) {
2440                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2441            }
2442            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2443            long identity = Binder.clearCallingIdentity();
2444            mockProvider.setLocation(loc);
2445            Binder.restoreCallingIdentity(identity);
2446        }
2447    }
2448
2449    @Override
2450    public void clearTestProviderLocation(String provider) {
2451        checkMockPermissionsSafe();
2452        synchronized (mLock) {
2453            MockProvider mockProvider = mMockProviders.get(provider);
2454            if (mockProvider == null) {
2455                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2456            }
2457            mockProvider.clearLocation();
2458        }
2459    }
2460
2461    @Override
2462    public void setTestProviderEnabled(String provider, boolean enabled) {
2463        checkMockPermissionsSafe();
2464        synchronized (mLock) {
2465            MockProvider mockProvider = mMockProviders.get(provider);
2466            if (mockProvider == null) {
2467                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2468            }
2469            long identity = Binder.clearCallingIdentity();
2470            if (enabled) {
2471                mockProvider.enable();
2472                mEnabledProviders.add(provider);
2473                mDisabledProviders.remove(provider);
2474            } else {
2475                mockProvider.disable();
2476                mEnabledProviders.remove(provider);
2477                mDisabledProviders.add(provider);
2478            }
2479            updateProvidersLocked();
2480            Binder.restoreCallingIdentity(identity);
2481        }
2482    }
2483
2484    @Override
2485    public void clearTestProviderEnabled(String provider) {
2486        checkMockPermissionsSafe();
2487        synchronized (mLock) {
2488            MockProvider mockProvider = mMockProviders.get(provider);
2489            if (mockProvider == null) {
2490                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2491            }
2492            long identity = Binder.clearCallingIdentity();
2493            mEnabledProviders.remove(provider);
2494            mDisabledProviders.remove(provider);
2495            updateProvidersLocked();
2496            Binder.restoreCallingIdentity(identity);
2497        }
2498    }
2499
2500    @Override
2501    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2502        checkMockPermissionsSafe();
2503        synchronized (mLock) {
2504            MockProvider mockProvider = mMockProviders.get(provider);
2505            if (mockProvider == null) {
2506                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2507            }
2508            mockProvider.setStatus(status, extras, updateTime);
2509        }
2510    }
2511
2512    @Override
2513    public void clearTestProviderStatus(String provider) {
2514        checkMockPermissionsSafe();
2515        synchronized (mLock) {
2516            MockProvider mockProvider = mMockProviders.get(provider);
2517            if (mockProvider == null) {
2518                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2519            }
2520            mockProvider.clearStatus();
2521        }
2522    }
2523
2524    private void log(String log) {
2525        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2526            Slog.d(TAG, log);
2527        }
2528    }
2529
2530    @Override
2531    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2532        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2533                != PackageManager.PERMISSION_GRANTED) {
2534            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2535                    + Binder.getCallingPid()
2536                    + ", uid=" + Binder.getCallingUid());
2537            return;
2538        }
2539
2540        synchronized (mLock) {
2541            pw.println("Current Location Manager state:");
2542            pw.println("  Location Listeners:");
2543            for (Receiver receiver : mReceivers.values()) {
2544                pw.println("    " + receiver);
2545            }
2546            pw.println("  Active Records by Provider:");
2547            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2548                pw.println("    " + entry.getKey() + ":");
2549                for (UpdateRecord record : entry.getValue()) {
2550                    pw.println("      " + record);
2551                }
2552            }
2553            pw.println("  Historical Records by Provider:");
2554            for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2555                    : mRequestStatistics.statistics.entrySet()) {
2556                PackageProviderKey key = entry.getKey();
2557                PackageStatistics stats = entry.getValue();
2558                pw.println("    " + key.packageName + ": " + key.providerName + ": " + stats);
2559            }
2560            pw.println("  Last Known Locations:");
2561            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2562                String provider = entry.getKey();
2563                Location location = entry.getValue();
2564                pw.println("    " + provider + ": " + location);
2565            }
2566
2567            pw.println("  Last Known Locations Coarse Intervals:");
2568            for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2569                String provider = entry.getKey();
2570                Location location = entry.getValue();
2571                pw.println("    " + provider + ": " + location);
2572            }
2573
2574            mGeofenceManager.dump(pw);
2575
2576            if (mEnabledProviders.size() > 0) {
2577                pw.println("  Enabled Providers:");
2578                for (String i : mEnabledProviders) {
2579                    pw.println("    " + i);
2580                }
2581
2582            }
2583            if (mDisabledProviders.size() > 0) {
2584                pw.println("  Disabled Providers:");
2585                for (String i : mDisabledProviders) {
2586                    pw.println("    " + i);
2587                }
2588            }
2589            pw.append("  ");
2590            mBlacklist.dump(pw);
2591            if (mMockProviders.size() > 0) {
2592                pw.println("  Mock Providers:");
2593                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2594                    i.getValue().dump(pw, "      ");
2595                }
2596            }
2597
2598            pw.append("  fudger: ");
2599            mLocationFudger.dump(fd, pw,  args);
2600
2601            if (args.length > 0 && "short".equals(args[0])) {
2602                return;
2603            }
2604            for (LocationProviderInterface provider: mProviders) {
2605                pw.print(provider.getName() + " Internal State");
2606                if (provider instanceof LocationProviderProxy) {
2607                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
2608                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
2609                }
2610                pw.println(":");
2611                provider.dump(fd, pw, args);
2612            }
2613        }
2614    }
2615}
2616