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