LocationManagerService.java revision f0c4f0ddb6167bac5f40b1f68044ecbf8486db7c
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.IGpsGeofenceHardware;
66import android.location.IGpsMeasurementsListener;
67import android.location.IGpsNavigationMessageListener;
68import android.location.IGpsStatusListener;
69import android.location.IGpsStatusProvider;
70import android.location.ILocationListener;
71import android.location.ILocationManager;
72import android.location.INetInitiatedListener;
73import android.location.Location;
74import android.location.LocationManager;
75import android.location.LocationProvider;
76import android.location.LocationRequest;
77import android.os.Binder;
78import android.os.Bundle;
79import android.os.Handler;
80import android.os.IBinder;
81import android.os.Looper;
82import android.os.Message;
83import android.os.PowerManager;
84import android.os.Process;
85import android.os.RemoteException;
86import android.os.SystemClock;
87import android.os.UserHandle;
88import android.os.UserManager;
89import android.os.WorkSource;
90import android.provider.Settings;
91import android.util.Log;
92import android.util.Slog;
93
94import java.io.FileDescriptor;
95import java.io.PrintWriter;
96import java.util.ArrayList;
97import java.util.Arrays;
98import java.util.HashMap;
99import java.util.HashSet;
100import java.util.List;
101import java.util.Map;
102import java.util.Set;
103
104/**
105 * The service class that manages LocationProviders and issues location
106 * updates and alerts.
107 */
108public class LocationManagerService extends ILocationManager.Stub {
109    private static final String TAG = "LocationManagerService";
110    public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
111
112    private static final String WAKELOCK_KEY = TAG;
113
114    // Location resolution level: no location data whatsoever
115    private static final int RESOLUTION_LEVEL_NONE = 0;
116    // Location resolution level: coarse location data only
117    private static final int RESOLUTION_LEVEL_COARSE = 1;
118    // Location resolution level: fine location data
119    private static final int RESOLUTION_LEVEL_FINE = 2;
120
121    private static final String ACCESS_MOCK_LOCATION =
122            android.Manifest.permission.ACCESS_MOCK_LOCATION;
123    private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
124            android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
125    private static final String INSTALL_LOCATION_PROVIDER =
126            android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
127
128    private static final String NETWORK_LOCATION_SERVICE_ACTION =
129            "com.android.location.service.v3.NetworkLocationProvider";
130    private static final String FUSED_LOCATION_SERVICE_ACTION =
131            "com.android.location.service.FusedLocationProvider";
132
133    private static final int MSG_LOCATION_CHANGED = 1;
134
135    private static final long NANOS_PER_MILLI = 1000000L;
136
137    // The maximum interval a location request can have and still be considered "high power".
138    private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
139
140    // Location Providers may sometimes deliver location updates
141    // slightly faster that requested - provide grace period so
142    // we don't unnecessarily filter events that are otherwise on
143    // time
144    private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
145
146    private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
147
148    private final Context mContext;
149    private final AppOpsManager mAppOps;
150
151    // used internally for synchronization
152    private final Object mLock = new Object();
153
154    // --- fields below are final after systemReady() ---
155    private LocationFudger mLocationFudger;
156    private GeofenceManager mGeofenceManager;
157    private PackageManager mPackageManager;
158    private PowerManager mPowerManager;
159    private UserManager mUserManager;
160    private GeocoderProxy mGeocodeProvider;
161    private IGpsStatusProvider mGpsStatusProvider;
162    private INetInitiatedListener mNetInitiatedListener;
163    private LocationWorkerHandler mLocationHandler;
164    private PassiveProvider mPassiveProvider;  // track passive provider for special cases
165    private LocationBlacklist mBlacklist;
166    private GpsMeasurementsProvider mGpsMeasurementsProvider;
167    private GpsNavigationMessageProvider mGpsNavigationMessageProvider;
168    private IGpsGeofenceHardware mGpsGeofenceProxy;
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
409        if (GpsLocationProvider.isSupported()) {
410            // Create a gps location provider
411            GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
412                    mLocationHandler.getLooper());
413            mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
414            mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
415            addProviderLocked(gpsProvider);
416            mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
417            mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
418            mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
419            mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
420        }
421
422        /*
423        Load package name(s) containing location provider support.
424        These packages can contain services implementing location providers:
425        Geocoder Provider, Network Location Provider, and
426        Fused Location Provider. They will each be searched for
427        service components implementing these providers.
428        The location framework also has support for installation
429        of new location providers at run-time. The new package does not
430        have to be explicitly listed here, however it must have a signature
431        that matches the signature of at least one package on this list.
432        */
433        Resources resources = mContext.getResources();
434        ArrayList<String> providerPackageNames = new ArrayList<String>();
435        String[] pkgs = resources.getStringArray(
436                com.android.internal.R.array.config_locationProviderPackageNames);
437        if (D) Log.d(TAG, "certificates for location providers pulled from: " +
438                Arrays.toString(pkgs));
439        if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
440
441        ensureFallbackFusedProviderPresentLocked(providerPackageNames);
442
443        // bind to network provider
444        LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
445                mContext,
446                LocationManager.NETWORK_PROVIDER,
447                NETWORK_LOCATION_SERVICE_ACTION,
448                com.android.internal.R.bool.config_enableNetworkLocationOverlay,
449                com.android.internal.R.string.config_networkLocationProviderPackageName,
450                com.android.internal.R.array.config_locationProviderPackageNames,
451                mLocationHandler);
452        if (networkProvider != null) {
453            mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
454            mProxyProviders.add(networkProvider);
455            addProviderLocked(networkProvider);
456        } else {
457            Slog.w(TAG,  "no network location provider found");
458        }
459
460        // bind to fused provider
461        LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
462                mContext,
463                LocationManager.FUSED_PROVIDER,
464                FUSED_LOCATION_SERVICE_ACTION,
465                com.android.internal.R.bool.config_enableFusedLocationOverlay,
466                com.android.internal.R.string.config_fusedLocationProviderPackageName,
467                com.android.internal.R.array.config_locationProviderPackageNames,
468                mLocationHandler);
469        if (fusedLocationProvider != null) {
470            addProviderLocked(fusedLocationProvider);
471            mProxyProviders.add(fusedLocationProvider);
472            mEnabledProviders.add(fusedLocationProvider.getName());
473            mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
474        } else {
475            Slog.e(TAG, "no fused location provider found",
476                    new IllegalStateException("Location service needs a fused location provider"));
477        }
478
479        // bind to geocoder provider
480        mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
481                com.android.internal.R.bool.config_enableGeocoderOverlay,
482                com.android.internal.R.string.config_geocoderProviderPackageName,
483                com.android.internal.R.array.config_locationProviderPackageNames,
484                mLocationHandler);
485        if (mGeocodeProvider == null) {
486            Slog.e(TAG,  "no geocoder provider found");
487        }
488
489        // bind to fused hardware provider if supported
490        // in devices without support, requesting an instance of FlpHardwareProvider will raise an
491        // exception, so make sure we only do that when supported
492        FlpHardwareProvider flpHardwareProvider;
493        if (FlpHardwareProvider.isSupported()) {
494            flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
495            FusedProxy fusedProxy = FusedProxy.createAndBind(
496                    mContext,
497                    mLocationHandler,
498                    flpHardwareProvider.getLocationHardware(),
499                    com.android.internal.R.bool.config_enableHardwareFlpOverlay,
500                    com.android.internal.R.string.config_hardwareFlpPackageName,
501                    com.android.internal.R.array.config_locationProviderPackageNames);
502            if (fusedProxy == null) {
503                Slog.e(TAG, "Unable to bind FusedProxy.");
504            }
505        } else {
506            flpHardwareProvider = null;
507            Slog.e(TAG, "FLP HAL not supported");
508        }
509
510        // bind to geofence provider
511        GeofenceProxy provider = GeofenceProxy.createAndBind(
512                mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
513                com.android.internal.R.string.config_geofenceProviderPackageName,
514                com.android.internal.R.array.config_locationProviderPackageNames,
515                mLocationHandler,
516                mGpsGeofenceProxy,
517                flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
518        if (provider == null) {
519            Slog.e(TAG,  "Unable to bind FLP Geofence proxy.");
520        }
521
522        // bind to the hardware activity recognition if supported
523        if (ActivityRecognitionHardware.isSupported()) {
524            ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
525                    mContext,
526                    mLocationHandler,
527                    ActivityRecognitionHardware.getInstance(mContext),
528                    com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
529                    com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
530                    com.android.internal.R.array.config_locationProviderPackageNames);
531
532            if (proxy == null) {
533                Slog.e(TAG, "Unable to bind ActivityRecognitionProxy.");
534            }
535        } else {
536            Slog.e(TAG, "Hardware Activity-Recognition not supported.");
537        }
538
539        String[] testProviderStrings = resources.getStringArray(
540                com.android.internal.R.array.config_testLocationProviders);
541        for (String testProviderString : testProviderStrings) {
542            String fragments[] = testProviderString.split(",");
543            String name = fragments[0].trim();
544            if (mProvidersByName.get(name) != null) {
545                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
546            }
547            ProviderProperties properties = new ProviderProperties(
548                    Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
549                    Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
550                    Boolean.parseBoolean(fragments[3]) /* requiresCell */,
551                    Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
552                    Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
553                    Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
554                    Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
555                    Integer.parseInt(fragments[8]) /* powerRequirement */,
556                    Integer.parseInt(fragments[9]) /* accuracy */);
557            addTestProviderLocked(name, properties);
558        }
559    }
560
561    /**
562     * Called when the device's active user changes.
563     * @param userId the new active user's UserId
564     */
565    private void switchUser(int userId) {
566        if (mCurrentUserId == userId) {
567            return;
568        }
569        mBlacklist.switchUser(userId);
570        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
571        synchronized (mLock) {
572            mLastLocation.clear();
573            mLastLocationCoarseInterval.clear();
574            for (LocationProviderInterface p : mProviders) {
575                updateProviderListenersLocked(p.getName(), false);
576            }
577            mCurrentUserId = userId;
578            updateUserProfiles(userId);
579            updateProvidersLocked();
580        }
581    }
582
583    /**
584     * A wrapper class holding either an ILocationListener or a PendingIntent to receive
585     * location updates.
586     */
587    private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
588        final int mUid;  // uid of receiver
589        final int mPid;  // pid of receiver
590        final String mPackageName;  // package name of receiver
591        final int mAllowedResolutionLevel;  // resolution level allowed to receiver
592
593        final ILocationListener mListener;
594        final PendingIntent mPendingIntent;
595        final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
596        final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
597        final Object mKey;
598
599        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
600
601        // True if app ops has started monitoring this receiver for locations.
602        boolean mOpMonitoring;
603        // True if app ops has started monitoring this receiver for high power (gps) locations.
604        boolean mOpHighPowerMonitoring;
605        int mPendingBroadcasts;
606        PowerManager.WakeLock mWakeLock;
607
608        Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
609                String packageName, WorkSource workSource, boolean hideFromAppOps) {
610            mListener = listener;
611            mPendingIntent = intent;
612            if (listener != null) {
613                mKey = listener.asBinder();
614            } else {
615                mKey = intent;
616            }
617            mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
618            mUid = uid;
619            mPid = pid;
620            mPackageName = packageName;
621            if (workSource != null && workSource.size() <= 0) {
622                workSource = null;
623            }
624            mWorkSource = workSource;
625            mHideFromAppOps = hideFromAppOps;
626
627            updateMonitoring(true);
628
629            // construct/configure wakelock
630            mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
631            if (workSource == null) {
632                workSource = new WorkSource(mUid, mPackageName);
633            }
634            mWakeLock.setWorkSource(workSource);
635        }
636
637        @Override
638        public boolean equals(Object otherObj) {
639            if (otherObj instanceof Receiver) {
640                return mKey.equals(((Receiver)otherObj).mKey);
641            }
642            return false;
643        }
644
645        @Override
646        public int hashCode() {
647            return mKey.hashCode();
648        }
649
650        @Override
651        public String toString() {
652            StringBuilder s = new StringBuilder();
653            s.append("Reciever[");
654            s.append(Integer.toHexString(System.identityHashCode(this)));
655            if (mListener != null) {
656                s.append(" listener");
657            } else {
658                s.append(" intent");
659            }
660            for (String p : mUpdateRecords.keySet()) {
661                s.append(" ").append(mUpdateRecords.get(p).toString());
662            }
663            s.append("]");
664            return s.toString();
665        }
666
667        /**
668         * Update AppOp monitoring for this receiver.
669         *
670         * @param allow If true receiver is currently active, if false it's been removed.
671         */
672        public void updateMonitoring(boolean allow) {
673            if (mHideFromAppOps) {
674                return;
675            }
676
677            boolean requestingLocation = false;
678            boolean requestingHighPowerLocation = false;
679            if (allow) {
680                // See if receiver has any enabled update records.  Also note if any update records
681                // are high power (has a high power provider with an interval under a threshold).
682                for (UpdateRecord updateRecord : mUpdateRecords.values()) {
683                    if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
684                        requestingLocation = true;
685                        LocationProviderInterface locationProvider
686                                = mProvidersByName.get(updateRecord.mProvider);
687                        ProviderProperties properties = locationProvider != null
688                                ? locationProvider.getProperties() : null;
689                        if (properties != null
690                                && properties.mPowerRequirement == Criteria.POWER_HIGH
691                                && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
692                            requestingHighPowerLocation = true;
693                            break;
694                        }
695                    }
696                }
697            }
698
699            // First update monitoring of any location request (including high power).
700            mOpMonitoring = updateMonitoring(
701                    requestingLocation,
702                    mOpMonitoring,
703                    AppOpsManager.OP_MONITOR_LOCATION);
704
705            // Now update monitoring of high power requests only.
706            boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
707            mOpHighPowerMonitoring = updateMonitoring(
708                    requestingHighPowerLocation,
709                    mOpHighPowerMonitoring,
710                    AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
711            if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
712                // Send an intent to notify that a high power request has been added/removed.
713                Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
714                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
715            }
716        }
717
718        /**
719         * Update AppOps monitoring for a single location request and op type.
720         *
721         * @param allowMonitoring True if monitoring is allowed for this request/op.
722         * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
723         * @param op AppOps code for the op to update.
724         * @return True if monitoring is on for this request/op after updating.
725         */
726        private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
727                int op) {
728            if (!currentlyMonitoring) {
729                if (allowMonitoring) {
730                    return mAppOps.startOpNoThrow(op, mUid, mPackageName)
731                            == AppOpsManager.MODE_ALLOWED;
732                }
733            } else {
734                if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
735                        != AppOpsManager.MODE_ALLOWED) {
736                    mAppOps.finishOp(op, mUid, mPackageName);
737                    return false;
738                }
739            }
740
741            return currentlyMonitoring;
742        }
743
744        public boolean isListener() {
745            return mListener != null;
746        }
747
748        public boolean isPendingIntent() {
749            return mPendingIntent != null;
750        }
751
752        public ILocationListener getListener() {
753            if (mListener != null) {
754                return mListener;
755            }
756            throw new IllegalStateException("Request for non-existent listener");
757        }
758
759        public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
760            if (mListener != null) {
761                try {
762                    synchronized (this) {
763                        // synchronize to ensure incrementPendingBroadcastsLocked()
764                        // is called before decrementPendingBroadcasts()
765                        mListener.onStatusChanged(provider, status, extras);
766                        // call this after broadcasting so we do not increment
767                        // if we throw an exeption.
768                        incrementPendingBroadcastsLocked();
769                    }
770                } catch (RemoteException e) {
771                    return false;
772                }
773            } else {
774                Intent statusChanged = new Intent();
775                statusChanged.putExtras(new Bundle(extras));
776                statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
777                try {
778                    synchronized (this) {
779                        // synchronize to ensure incrementPendingBroadcastsLocked()
780                        // is called before decrementPendingBroadcasts()
781                        mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
782                                getResolutionPermission(mAllowedResolutionLevel));
783                        // call this after broadcasting so we do not increment
784                        // if we throw an exeption.
785                        incrementPendingBroadcastsLocked();
786                    }
787                } catch (PendingIntent.CanceledException e) {
788                    return false;
789                }
790            }
791            return true;
792        }
793
794        public boolean callLocationChangedLocked(Location location) {
795            if (mListener != null) {
796                try {
797                    synchronized (this) {
798                        // synchronize to ensure incrementPendingBroadcastsLocked()
799                        // is called before decrementPendingBroadcasts()
800                        mListener.onLocationChanged(new Location(location));
801                        // call this after broadcasting so we do not increment
802                        // if we throw an exeption.
803                        incrementPendingBroadcastsLocked();
804                    }
805                } catch (RemoteException e) {
806                    return false;
807                }
808            } else {
809                Intent locationChanged = new Intent();
810                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
811                try {
812                    synchronized (this) {
813                        // synchronize to ensure incrementPendingBroadcastsLocked()
814                        // is called before decrementPendingBroadcasts()
815                        mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
816                                getResolutionPermission(mAllowedResolutionLevel));
817                        // call this after broadcasting so we do not increment
818                        // if we throw an exeption.
819                        incrementPendingBroadcastsLocked();
820                    }
821                } catch (PendingIntent.CanceledException e) {
822                    return false;
823                }
824            }
825            return true;
826        }
827
828        public boolean callProviderEnabledLocked(String provider, boolean enabled) {
829            // First update AppOp monitoring.
830            // An app may get/lose location access as providers are enabled/disabled.
831            updateMonitoring(true);
832
833            if (mListener != null) {
834                try {
835                    synchronized (this) {
836                        // synchronize to ensure incrementPendingBroadcastsLocked()
837                        // is called before decrementPendingBroadcasts()
838                        if (enabled) {
839                            mListener.onProviderEnabled(provider);
840                        } else {
841                            mListener.onProviderDisabled(provider);
842                        }
843                        // call this after broadcasting so we do not increment
844                        // if we throw an exeption.
845                        incrementPendingBroadcastsLocked();
846                    }
847                } catch (RemoteException e) {
848                    return false;
849                }
850            } else {
851                Intent providerIntent = new Intent();
852                providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
853                try {
854                    synchronized (this) {
855                        // synchronize to ensure incrementPendingBroadcastsLocked()
856                        // is called before decrementPendingBroadcasts()
857                        mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
858                                getResolutionPermission(mAllowedResolutionLevel));
859                        // call this after broadcasting so we do not increment
860                        // if we throw an exeption.
861                        incrementPendingBroadcastsLocked();
862                    }
863                } catch (PendingIntent.CanceledException e) {
864                    return false;
865                }
866            }
867            return true;
868        }
869
870        @Override
871        public void binderDied() {
872            if (D) Log.d(TAG, "Location listener died");
873
874            synchronized (mLock) {
875                removeUpdatesLocked(this);
876            }
877            synchronized (this) {
878                clearPendingBroadcastsLocked();
879            }
880        }
881
882        @Override
883        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
884                int resultCode, String resultData, Bundle resultExtras) {
885            synchronized (this) {
886                decrementPendingBroadcastsLocked();
887            }
888        }
889
890        // this must be called while synchronized by caller in a synchronized block
891        // containing the sending of the broadcaset
892        private void incrementPendingBroadcastsLocked() {
893            if (mPendingBroadcasts++ == 0) {
894                mWakeLock.acquire();
895            }
896        }
897
898        private void decrementPendingBroadcastsLocked() {
899            if (--mPendingBroadcasts == 0) {
900                if (mWakeLock.isHeld()) {
901                    mWakeLock.release();
902                }
903            }
904        }
905
906        public void clearPendingBroadcastsLocked() {
907            if (mPendingBroadcasts > 0) {
908                mPendingBroadcasts = 0;
909                if (mWakeLock.isHeld()) {
910                    mWakeLock.release();
911                }
912            }
913        }
914    }
915
916    @Override
917    public void locationCallbackFinished(ILocationListener listener) {
918        //Do not use getReceiverLocked here as that will add the ILocationListener to
919        //the receiver list if it is not found.  If it is not found then the
920        //LocationListener was removed when it had a pending broadcast and should
921        //not be added back.
922        synchronized (mLock) {
923            IBinder binder = listener.asBinder();
924            Receiver receiver = mReceivers.get(binder);
925            if (receiver != null) {
926                synchronized (receiver) {
927                    // so wakelock calls will succeed
928                    long identity = Binder.clearCallingIdentity();
929                    receiver.decrementPendingBroadcastsLocked();
930                    Binder.restoreCallingIdentity(identity);
931                }
932            }
933        }
934    }
935
936    private void addProviderLocked(LocationProviderInterface provider) {
937        mProviders.add(provider);
938        mProvidersByName.put(provider.getName(), provider);
939    }
940
941    private void removeProviderLocked(LocationProviderInterface provider) {
942        provider.disable();
943        mProviders.remove(provider);
944        mProvidersByName.remove(provider.getName());
945    }
946
947    /**
948     * Returns "true" if access to the specified location provider is allowed by the current
949     * user's settings. Access to all location providers is forbidden to non-location-provider
950     * processes belonging to background users.
951     *
952     * @param provider the name of the location provider
953     * @return
954     */
955    private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
956        if (mEnabledProviders.contains(provider)) {
957            return true;
958        }
959        if (mDisabledProviders.contains(provider)) {
960            return false;
961        }
962        // Use system settings
963        ContentResolver resolver = mContext.getContentResolver();
964
965        return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
966    }
967
968    /**
969     * Returns "true" if access to the specified location provider is allowed by the specified
970     * user's settings. Access to all location providers is forbidden to non-location-provider
971     * processes belonging to background users.
972     *
973     * @param provider the name of the location provider
974     * @param uid the requestor's UID
975     * @return
976     */
977    private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
978        if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
979            return false;
980        }
981        return isAllowedByCurrentUserSettingsLocked(provider);
982    }
983
984    /**
985     * Returns the permission string associated with the specified resolution level.
986     *
987     * @param resolutionLevel the resolution level
988     * @return the permission string
989     */
990    private String getResolutionPermission(int resolutionLevel) {
991        switch (resolutionLevel) {
992            case RESOLUTION_LEVEL_FINE:
993                return android.Manifest.permission.ACCESS_FINE_LOCATION;
994            case RESOLUTION_LEVEL_COARSE:
995                return android.Manifest.permission.ACCESS_COARSE_LOCATION;
996            default:
997                return null;
998        }
999    }
1000
1001    /**
1002     * Returns the resolution level allowed to the given PID/UID pair.
1003     *
1004     * @param pid the PID
1005     * @param uid the UID
1006     * @return resolution level allowed to the pid/uid pair
1007     */
1008    private int getAllowedResolutionLevel(int pid, int uid) {
1009        if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1010                pid, uid) == PackageManager.PERMISSION_GRANTED) {
1011            return RESOLUTION_LEVEL_FINE;
1012        } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1013                pid, uid) == PackageManager.PERMISSION_GRANTED) {
1014            return RESOLUTION_LEVEL_COARSE;
1015        } else {
1016            return RESOLUTION_LEVEL_NONE;
1017        }
1018    }
1019
1020    /**
1021     * Returns the resolution level allowed to the caller
1022     *
1023     * @return resolution level allowed to caller
1024     */
1025    private int getCallerAllowedResolutionLevel() {
1026        return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1027    }
1028
1029    /**
1030     * Throw SecurityException if specified resolution level is insufficient to use geofences.
1031     *
1032     * @param allowedResolutionLevel resolution level allowed to caller
1033     */
1034    private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1035        if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1036            throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1037        }
1038    }
1039
1040    /**
1041     * Return the minimum resolution level required to use the specified location provider.
1042     *
1043     * @param provider the name of the location provider
1044     * @return minimum resolution level required for provider
1045     */
1046    private int getMinimumResolutionLevelForProviderUse(String provider) {
1047        if (LocationManager.GPS_PROVIDER.equals(provider) ||
1048                LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1049            // gps and passive providers require FINE permission
1050            return RESOLUTION_LEVEL_FINE;
1051        } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1052                LocationManager.FUSED_PROVIDER.equals(provider)) {
1053            // network and fused providers are ok with COARSE or FINE
1054            return RESOLUTION_LEVEL_COARSE;
1055        } else {
1056            // mock providers
1057            LocationProviderInterface lp = mMockProviders.get(provider);
1058            if (lp != null) {
1059                ProviderProperties properties = lp.getProperties();
1060                if (properties != null) {
1061                    if (properties.mRequiresSatellite) {
1062                        // provider requiring satellites require FINE permission
1063                        return RESOLUTION_LEVEL_FINE;
1064                    } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1065                        // provider requiring network and or cell require COARSE or FINE
1066                        return RESOLUTION_LEVEL_COARSE;
1067                    }
1068                }
1069            }
1070        }
1071        return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
1072    }
1073
1074    /**
1075     * Throw SecurityException if specified resolution level is insufficient to use the named
1076     * location provider.
1077     *
1078     * @param allowedResolutionLevel resolution level allowed to caller
1079     * @param providerName the name of the location provider
1080     */
1081    private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1082            String providerName) {
1083        int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1084        if (allowedResolutionLevel < requiredResolutionLevel) {
1085            switch (requiredResolutionLevel) {
1086                case RESOLUTION_LEVEL_FINE:
1087                    throw new SecurityException("\"" + providerName + "\" location provider " +
1088                            "requires ACCESS_FINE_LOCATION permission.");
1089                case RESOLUTION_LEVEL_COARSE:
1090                    throw new SecurityException("\"" + providerName + "\" location provider " +
1091                            "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1092                default:
1093                    throw new SecurityException("Insufficient permission for \"" + providerName +
1094                            "\" location provider.");
1095            }
1096        }
1097    }
1098
1099    /**
1100     * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1101     * for battery).
1102     */
1103    private void checkDeviceStatsAllowed() {
1104        mContext.enforceCallingOrSelfPermission(
1105                android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1106    }
1107
1108    private void checkUpdateAppOpsAllowed() {
1109        mContext.enforceCallingOrSelfPermission(
1110                android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1111    }
1112
1113    public static int resolutionLevelToOp(int allowedResolutionLevel) {
1114        if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1115            if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
1116                return AppOpsManager.OP_COARSE_LOCATION;
1117            } else {
1118                return AppOpsManager.OP_FINE_LOCATION;
1119            }
1120        }
1121        return -1;
1122    }
1123
1124    boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
1125        int op = resolutionLevelToOp(allowedResolutionLevel);
1126        if (op >= 0) {
1127            if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1128                return false;
1129            }
1130        }
1131        return true;
1132    }
1133
1134    boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
1135        int op = resolutionLevelToOp(allowedResolutionLevel);
1136        if (op >= 0) {
1137            if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1138                return false;
1139            }
1140        }
1141        return true;
1142    }
1143
1144    /**
1145     * Returns all providers by name, including passive, but excluding
1146     * fused, also including ones that are not permitted to
1147     * be accessed by the calling activity or are currently disabled.
1148     */
1149    @Override
1150    public List<String> getAllProviders() {
1151        ArrayList<String> out;
1152        synchronized (mLock) {
1153            out = new ArrayList<String>(mProviders.size());
1154            for (LocationProviderInterface provider : mProviders) {
1155                String name = provider.getName();
1156                if (LocationManager.FUSED_PROVIDER.equals(name)) {
1157                    continue;
1158                }
1159                out.add(name);
1160            }
1161        }
1162
1163        if (D) Log.d(TAG, "getAllProviders()=" + out);
1164        return out;
1165    }
1166
1167    /**
1168     * Return all providers by name, that match criteria and are optionally
1169     * enabled.
1170     * Can return passive provider, but never returns fused provider.
1171     */
1172    @Override
1173    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
1174        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1175        ArrayList<String> out;
1176        int uid = Binder.getCallingUid();;
1177        long identity = Binder.clearCallingIdentity();
1178        try {
1179            synchronized (mLock) {
1180                out = new ArrayList<String>(mProviders.size());
1181                for (LocationProviderInterface provider : mProviders) {
1182                    String name = provider.getName();
1183                    if (LocationManager.FUSED_PROVIDER.equals(name)) {
1184                        continue;
1185                    }
1186                    if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
1187                        if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
1188                            continue;
1189                        }
1190                        if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1191                                name, provider.getProperties(), criteria)) {
1192                            continue;
1193                        }
1194                        out.add(name);
1195                    }
1196                }
1197            }
1198        } finally {
1199            Binder.restoreCallingIdentity(identity);
1200        }
1201
1202        if (D) Log.d(TAG, "getProviders()=" + out);
1203        return out;
1204    }
1205
1206    /**
1207     * Return the name of the best provider given a Criteria object.
1208     * This method has been deprecated from the public API,
1209     * and the whole LocationProvider (including #meetsCriteria)
1210     * has been deprecated as well. So this method now uses
1211     * some simplified logic.
1212     */
1213    @Override
1214    public String getBestProvider(Criteria criteria, boolean enabledOnly) {
1215        String result = null;
1216
1217        List<String> providers = getProviders(criteria, enabledOnly);
1218        if (!providers.isEmpty()) {
1219            result = pickBest(providers);
1220            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1221            return result;
1222        }
1223        providers = getProviders(null, enabledOnly);
1224        if (!providers.isEmpty()) {
1225            result = pickBest(providers);
1226            if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1227            return result;
1228        }
1229
1230        if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1231        return null;
1232    }
1233
1234    private String pickBest(List<String> providers) {
1235        if (providers.contains(LocationManager.GPS_PROVIDER)) {
1236            return LocationManager.GPS_PROVIDER;
1237        } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1238            return LocationManager.NETWORK_PROVIDER;
1239        } else {
1240            return providers.get(0);
1241        }
1242    }
1243
1244    @Override
1245    public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1246        LocationProviderInterface p = mProvidersByName.get(provider);
1247        if (p == null) {
1248            throw new IllegalArgumentException("provider=" + provider);
1249        }
1250
1251        boolean result = LocationProvider.propertiesMeetCriteria(
1252                p.getName(), p.getProperties(), criteria);
1253        if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1254        return result;
1255    }
1256
1257    private void updateProvidersLocked() {
1258        boolean changesMade = false;
1259        for (int i = mProviders.size() - 1; i >= 0; i--) {
1260            LocationProviderInterface p = mProviders.get(i);
1261            boolean isEnabled = p.isEnabled();
1262            String name = p.getName();
1263            boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
1264            if (isEnabled && !shouldBeEnabled) {
1265                updateProviderListenersLocked(name, false);
1266                // If any provider has been disabled, clear all last locations for all providers.
1267                // This is to be on the safe side in case a provider has location derived from
1268                // this disabled provider.
1269                mLastLocation.clear();
1270                mLastLocationCoarseInterval.clear();
1271                changesMade = true;
1272            } else if (!isEnabled && shouldBeEnabled) {
1273                updateProviderListenersLocked(name, true);
1274                changesMade = true;
1275            }
1276        }
1277        if (changesMade) {
1278            mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1279                    UserHandle.ALL);
1280            mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1281                    UserHandle.ALL);
1282        }
1283    }
1284
1285    private void updateProviderListenersLocked(String provider, boolean enabled) {
1286        int listeners = 0;
1287
1288        LocationProviderInterface p = mProvidersByName.get(provider);
1289        if (p == null) return;
1290
1291        ArrayList<Receiver> deadReceivers = null;
1292
1293        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1294        if (records != null) {
1295            final int N = records.size();
1296            for (int i = 0; i < N; i++) {
1297                UpdateRecord record = records.get(i);
1298                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
1299                    // Sends a notification message to the receiver
1300                    if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1301                        if (deadReceivers == null) {
1302                            deadReceivers = new ArrayList<Receiver>();
1303                        }
1304                        deadReceivers.add(record.mReceiver);
1305                    }
1306                    listeners++;
1307                }
1308            }
1309        }
1310
1311        if (deadReceivers != null) {
1312            for (int i = deadReceivers.size() - 1; i >= 0; i--) {
1313                removeUpdatesLocked(deadReceivers.get(i));
1314            }
1315        }
1316
1317        if (enabled) {
1318            p.enable();
1319            if (listeners > 0) {
1320                applyRequirementsLocked(provider);
1321            }
1322        } else {
1323            p.disable();
1324        }
1325    }
1326
1327    private void applyRequirementsLocked(String provider) {
1328        LocationProviderInterface p = mProvidersByName.get(provider);
1329        if (p == null) return;
1330
1331        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1332        WorkSource worksource = new WorkSource();
1333        ProviderRequest providerRequest = new ProviderRequest();
1334
1335        if (records != null) {
1336            for (UpdateRecord record : records) {
1337                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
1338                    if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1339                            record.mReceiver.mAllowedResolutionLevel)) {
1340                        LocationRequest locationRequest = record.mRequest;
1341                        providerRequest.locationRequests.add(locationRequest);
1342                        if (locationRequest.getInterval() < providerRequest.interval) {
1343                            providerRequest.reportLocation = true;
1344                            providerRequest.interval = locationRequest.getInterval();
1345                        }
1346                    }
1347                }
1348            }
1349
1350            if (providerRequest.reportLocation) {
1351                // calculate who to blame for power
1352                // This is somewhat arbitrary. We pick a threshold interval
1353                // that is slightly higher that the minimum interval, and
1354                // spread the blame across all applications with a request
1355                // under that threshold.
1356                long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1357                for (UpdateRecord record : records) {
1358                    if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
1359                        LocationRequest locationRequest = record.mRequest;
1360                        if (locationRequest.getInterval() <= thresholdInterval) {
1361                            if (record.mReceiver.mWorkSource != null
1362                                    && record.mReceiver.mWorkSource.size() > 0
1363                                    && record.mReceiver.mWorkSource.getName(0) != null) {
1364                                // Assign blame to another work source.
1365                                // Can only assign blame if the WorkSource contains names.
1366                                worksource.add(record.mReceiver.mWorkSource);
1367                            } else {
1368                                // Assign blame to caller.
1369                                worksource.add(
1370                                        record.mReceiver.mUid,
1371                                        record.mReceiver.mPackageName);
1372                            }
1373                        }
1374                    }
1375                }
1376            }
1377        }
1378
1379        if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1380        p.setRequest(providerRequest, worksource);
1381    }
1382
1383    private class UpdateRecord {
1384        final String mProvider;
1385        final LocationRequest mRequest;
1386        final Receiver mReceiver;
1387        Location mLastFixBroadcast;
1388        long mLastStatusBroadcast;
1389
1390        /**
1391         * Note: must be constructed with lock held.
1392         */
1393        UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
1394            mProvider = provider;
1395            mRequest = request;
1396            mReceiver = receiver;
1397
1398            ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1399            if (records == null) {
1400                records = new ArrayList<UpdateRecord>();
1401                mRecordsByProvider.put(provider, records);
1402            }
1403            if (!records.contains(this)) {
1404                records.add(this);
1405            }
1406
1407            // Update statistics for historical location requests by package/provider
1408            mRequestStatistics.startRequesting(
1409                    mReceiver.mPackageName, provider, request.getInterval());
1410        }
1411
1412        /**
1413         * Method to be called when a record will no longer be used.
1414         */
1415        void disposeLocked(boolean removeReceiver) {
1416            mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1417
1418            // remove from mRecordsByProvider
1419            ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1420            if (globalRecords != null) {
1421                globalRecords.remove(this);
1422            }
1423
1424            if (!removeReceiver) return;  // the caller will handle the rest
1425
1426            // remove from Receiver#mUpdateRecords
1427            HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1428            if (receiverRecords != null) {
1429                receiverRecords.remove(this.mProvider);
1430
1431                // and also remove the Receiver if it has no more update records
1432                if (removeReceiver && receiverRecords.size() == 0) {
1433                    removeUpdatesLocked(mReceiver);
1434                }
1435            }
1436        }
1437
1438        @Override
1439        public String toString() {
1440            StringBuilder s = new StringBuilder();
1441            s.append("UpdateRecord[");
1442            s.append(mProvider);
1443            s.append(' ').append(mReceiver.mPackageName).append('(');
1444            s.append(mReceiver.mUid).append(')');
1445            s.append(' ').append(mRequest);
1446            s.append(']');
1447            return s.toString();
1448        }
1449    }
1450
1451    private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
1452            String packageName, WorkSource workSource, boolean hideFromAppOps) {
1453        IBinder binder = listener.asBinder();
1454        Receiver receiver = mReceivers.get(binder);
1455        if (receiver == null) {
1456            receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1457                    hideFromAppOps);
1458            try {
1459                receiver.getListener().asBinder().linkToDeath(receiver, 0);
1460            } catch (RemoteException e) {
1461                Slog.e(TAG, "linkToDeath failed:", e);
1462                return null;
1463            }
1464            mReceivers.put(binder, receiver);
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 || mGpsMeasurementsProvider == null) {
1860            return false;
1861        }
1862        return mGpsMeasurementsProvider.addListener(listener);
1863    }
1864
1865    @Override
1866    public void removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
1867        if (mGpsMeasurementsProvider != null) {
1868            mGpsMeasurementsProvider.removeListener(listener);
1869        }
1870    }
1871
1872    @Override
1873    public boolean addGpsNavigationMessageListener(
1874            IGpsNavigationMessageListener listener,
1875            String packageName) {
1876        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1877        checkResolutionLevelIsSufficientForProviderUse(
1878                allowedResolutionLevel,
1879                LocationManager.GPS_PROVIDER);
1880
1881        int uid = Binder.getCallingUid();
1882        long identity = Binder.clearCallingIdentity();
1883        boolean hasLocationAccess;
1884        try {
1885            hasLocationAccess = checkLocationAccess(uid, packageName, allowedResolutionLevel);
1886        } finally {
1887            Binder.restoreCallingIdentity(identity);
1888        }
1889
1890        if (!hasLocationAccess || mGpsNavigationMessageProvider == null) {
1891            return false;
1892        }
1893        return mGpsNavigationMessageProvider.addListener(listener);
1894    }
1895
1896    @Override
1897    public void removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
1898        if (mGpsNavigationMessageProvider != null) {
1899            mGpsNavigationMessageProvider.removeListener(listener);
1900        }
1901    }
1902
1903    @Override
1904    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1905        if (provider == null) {
1906            // throw NullPointerException to remain compatible with previous implementation
1907            throw new NullPointerException();
1908        }
1909        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1910                provider);
1911
1912        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1913        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1914                != PackageManager.PERMISSION_GRANTED)) {
1915            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1916        }
1917
1918        synchronized (mLock) {
1919            LocationProviderInterface p = mProvidersByName.get(provider);
1920            if (p == null) return false;
1921
1922            return p.sendExtraCommand(command, extras);
1923        }
1924    }
1925
1926    @Override
1927    public boolean sendNiResponse(int notifId, int userResponse) {
1928        if (Binder.getCallingUid() != Process.myUid()) {
1929            throw new SecurityException(
1930                    "calling sendNiResponse from outside of the system is not allowed");
1931        }
1932        try {
1933            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1934        } catch (RemoteException e) {
1935            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1936            return false;
1937        }
1938    }
1939
1940    /**
1941     * @return null if the provider does not exist
1942     * @throws SecurityException if the provider is not allowed to be
1943     * accessed by the caller
1944     */
1945    @Override
1946    public ProviderProperties getProviderProperties(String provider) {
1947        if (mProvidersByName.get(provider) == null) {
1948            return null;
1949        }
1950
1951        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1952                provider);
1953
1954        LocationProviderInterface p;
1955        synchronized (mLock) {
1956            p = mProvidersByName.get(provider);
1957        }
1958
1959        if (p == null) return null;
1960        return p.getProperties();
1961    }
1962
1963    @Override
1964    public boolean isProviderEnabled(String provider) {
1965        // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
1966        // so we discourage its use
1967        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1968
1969        int uid = Binder.getCallingUid();
1970        long identity = Binder.clearCallingIdentity();
1971        try {
1972            synchronized (mLock) {
1973                LocationProviderInterface p = mProvidersByName.get(provider);
1974                if (p == null) return false;
1975
1976                return isAllowedByUserSettingsLocked(provider, uid);
1977            }
1978        } finally {
1979            Binder.restoreCallingIdentity(identity);
1980        }
1981    }
1982
1983    /**
1984     * Returns "true" if the UID belongs to a bound location provider.
1985     *
1986     * @param uid the uid
1987     * @return true if uid belongs to a bound location provider
1988     */
1989    private boolean isUidALocationProvider(int uid) {
1990        if (uid == Process.SYSTEM_UID) {
1991            return true;
1992        }
1993        if (mGeocodeProvider != null) {
1994            if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1995        }
1996        for (LocationProviderProxy proxy : mProxyProviders) {
1997            if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
1998        }
1999        return false;
2000    }
2001
2002    private void checkCallerIsProvider() {
2003        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2004                == PackageManager.PERMISSION_GRANTED) {
2005            return;
2006        }
2007
2008        // Previously we only used the INSTALL_LOCATION_PROVIDER
2009        // check. But that is system or signature
2010        // protection level which is not flexible enough for
2011        // providers installed oustide the system image. So
2012        // also allow providers with a UID matching the
2013        // currently bound package name
2014
2015        if (isUidALocationProvider(Binder.getCallingUid())) {
2016            return;
2017        }
2018
2019        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2020                "or UID of a currently bound location provider");
2021    }
2022
2023    /**
2024     * Returns true if the given package belongs to the given uid.
2025     */
2026    private boolean doesUidHavePackage(int uid, String packageName) {
2027        if (packageName == null) {
2028            return false;
2029        }
2030        String[] packageNames = mPackageManager.getPackagesForUid(uid);
2031        if (packageNames == null) {
2032            return false;
2033        }
2034        for (String name : packageNames) {
2035            if (packageName.equals(name)) {
2036                return true;
2037            }
2038        }
2039        return false;
2040    }
2041
2042    @Override
2043    public void reportLocation(Location location, boolean passive) {
2044        checkCallerIsProvider();
2045
2046        if (!location.isComplete()) {
2047            Log.w(TAG, "Dropping incomplete location: " + location);
2048            return;
2049        }
2050
2051        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2052        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
2053        m.arg1 = (passive ? 1 : 0);
2054        mLocationHandler.sendMessageAtFrontOfQueue(m);
2055    }
2056
2057
2058    private static boolean shouldBroadcastSafe(
2059            Location loc, Location lastLoc, UpdateRecord record, long now) {
2060        // Always broadcast the first update
2061        if (lastLoc == null) {
2062            return true;
2063        }
2064
2065        // Check whether sufficient time has passed
2066        long minTime = record.mRequest.getFastestInterval();
2067        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2068                / NANOS_PER_MILLI;
2069        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
2070            return false;
2071        }
2072
2073        // Check whether sufficient distance has been traveled
2074        double minDistance = record.mRequest.getSmallestDisplacement();
2075        if (minDistance > 0.0) {
2076            if (loc.distanceTo(lastLoc) <= minDistance) {
2077                return false;
2078            }
2079        }
2080
2081        // Check whether sufficient number of udpates is left
2082        if (record.mRequest.getNumUpdates() <= 0) {
2083            return false;
2084        }
2085
2086        // Check whether the expiry date has passed
2087        if (record.mRequest.getExpireAt() < now) {
2088            return false;
2089        }
2090
2091        return true;
2092    }
2093
2094    private void handleLocationChangedLocked(Location location, boolean passive) {
2095        if (D) Log.d(TAG, "incoming location: " + location);
2096
2097        long now = SystemClock.elapsedRealtime();
2098        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
2099
2100        // Skip if the provider is unknown.
2101        LocationProviderInterface p = mProvidersByName.get(provider);
2102        if (p == null) return;
2103
2104        // Update last known locations
2105        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2106        Location lastNoGPSLocation = null;
2107        Location lastLocation = mLastLocation.get(provider);
2108        if (lastLocation == null) {
2109            lastLocation = new Location(provider);
2110            mLastLocation.put(provider, lastLocation);
2111        } else {
2112            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2113            if (noGPSLocation == null && lastNoGPSLocation != null) {
2114                // New location has no no-GPS location: adopt last no-GPS location. This is set
2115                // directly into location because we do not want to notify COARSE clients.
2116                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2117            }
2118        }
2119        lastLocation.set(location);
2120
2121        // Update last known coarse interval location if enough time has passed.
2122        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2123        if (lastLocationCoarseInterval == null) {
2124            lastLocationCoarseInterval = new Location(location);
2125            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2126        }
2127        long timeDiffNanos = location.getElapsedRealtimeNanos()
2128                - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2129        if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2130            lastLocationCoarseInterval.set(location);
2131        }
2132        // Don't ever return a coarse location that is more recent than the allowed update
2133        // interval (i.e. don't allow an app to keep registering and unregistering for
2134        // location updates to overcome the minimum interval).
2135        noGPSLocation =
2136                lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2137
2138        // Skip if there are no UpdateRecords for this provider.
2139        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2140        if (records == null || records.size() == 0) return;
2141
2142        // Fetch coarse location
2143        Location coarseLocation = null;
2144        if (noGPSLocation != null) {
2145            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2146        }
2147
2148        // Fetch latest status update time
2149        long newStatusUpdateTime = p.getStatusUpdateTime();
2150
2151        // Get latest status
2152        Bundle extras = new Bundle();
2153        int status = p.getStatus(extras);
2154
2155        ArrayList<Receiver> deadReceivers = null;
2156        ArrayList<UpdateRecord> deadUpdateRecords = null;
2157
2158        // Broadcast location or status to all listeners
2159        for (UpdateRecord r : records) {
2160            Receiver receiver = r.mReceiver;
2161            boolean receiverDead = false;
2162
2163            int receiverUserId = UserHandle.getUserId(receiver.mUid);
2164            if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
2165                if (D) {
2166                    Log.d(TAG, "skipping loc update for background user " + receiverUserId +
2167                            " (current user: " + mCurrentUserId + ", app: " +
2168                            receiver.mPackageName + ")");
2169                }
2170                continue;
2171            }
2172
2173            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2174                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2175                        receiver.mPackageName);
2176                continue;
2177            }
2178
2179            if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
2180                    receiver.mAllowedResolutionLevel)) {
2181                if (D) Log.d(TAG, "skipping loc update for no op app: " +
2182                        receiver.mPackageName);
2183                continue;
2184            }
2185
2186            Location notifyLocation = null;
2187            if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2188                notifyLocation = coarseLocation;  // use coarse location
2189            } else {
2190                notifyLocation = lastLocation;  // use fine location
2191            }
2192            if (notifyLocation != null) {
2193                Location lastLoc = r.mLastFixBroadcast;
2194                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
2195                    if (lastLoc == null) {
2196                        lastLoc = new Location(notifyLocation);
2197                        r.mLastFixBroadcast = lastLoc;
2198                    } else {
2199                        lastLoc.set(notifyLocation);
2200                    }
2201                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
2202                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2203                        receiverDead = true;
2204                    }
2205                    r.mRequest.decrementNumUpdates();
2206                }
2207            }
2208
2209            long prevStatusUpdateTime = r.mLastStatusBroadcast;
2210            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
2211                    (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
2212
2213                r.mLastStatusBroadcast = newStatusUpdateTime;
2214                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
2215                    receiverDead = true;
2216                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
2217                }
2218            }
2219
2220            // track expired records
2221            if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
2222                if (deadUpdateRecords == null) {
2223                    deadUpdateRecords = new ArrayList<UpdateRecord>();
2224                }
2225                deadUpdateRecords.add(r);
2226            }
2227            // track dead receivers
2228            if (receiverDead) {
2229                if (deadReceivers == null) {
2230                    deadReceivers = new ArrayList<Receiver>();
2231                }
2232                if (!deadReceivers.contains(receiver)) {
2233                    deadReceivers.add(receiver);
2234                }
2235            }
2236        }
2237
2238        // remove dead records and receivers outside the loop
2239        if (deadReceivers != null) {
2240            for (Receiver receiver : deadReceivers) {
2241                removeUpdatesLocked(receiver);
2242            }
2243        }
2244        if (deadUpdateRecords != null) {
2245            for (UpdateRecord r : deadUpdateRecords) {
2246                r.disposeLocked(true);
2247            }
2248            applyRequirementsLocked(provider);
2249        }
2250    }
2251
2252    private class LocationWorkerHandler extends Handler {
2253        public LocationWorkerHandler(Looper looper) {
2254            super(looper, null, true);
2255        }
2256
2257        @Override
2258        public void handleMessage(Message msg) {
2259            switch (msg.what) {
2260                case MSG_LOCATION_CHANGED:
2261                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2262                    break;
2263            }
2264        }
2265    }
2266
2267    private boolean isMockProvider(String provider) {
2268        synchronized (mLock) {
2269            return mMockProviders.containsKey(provider);
2270        }
2271    }
2272
2273    private void handleLocationChanged(Location location, boolean passive) {
2274        // create a working copy of the incoming Location so that the service can modify it without
2275        // disturbing the caller's copy
2276        Location myLocation = new Location(location);
2277        String provider = myLocation.getProvider();
2278
2279        // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2280        // bit if location did not come from a mock provider because passive/fused providers can
2281        // forward locations from mock providers, and should not grant them legitimacy in doing so.
2282        if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2283            myLocation.setIsFromMockProvider(true);
2284        }
2285
2286        synchronized (mLock) {
2287            if (isAllowedByCurrentUserSettingsLocked(provider)) {
2288                if (!passive) {
2289                    // notify passive provider of the new location
2290                    mPassiveProvider.updateLocation(myLocation);
2291                }
2292                handleLocationChangedLocked(myLocation, passive);
2293            }
2294        }
2295    }
2296
2297    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2298        @Override
2299        public void onPackageDisappeared(String packageName, int reason) {
2300            // remove all receivers associated with this package name
2301            synchronized (mLock) {
2302                ArrayList<Receiver> deadReceivers = null;
2303
2304                for (Receiver receiver : mReceivers.values()) {
2305                    if (receiver.mPackageName.equals(packageName)) {
2306                        if (deadReceivers == null) {
2307                            deadReceivers = new ArrayList<Receiver>();
2308                        }
2309                        deadReceivers.add(receiver);
2310                    }
2311                }
2312
2313                // perform removal outside of mReceivers loop
2314                if (deadReceivers != null) {
2315                    for (Receiver receiver : deadReceivers) {
2316                        removeUpdatesLocked(receiver);
2317                    }
2318                }
2319            }
2320        }
2321    };
2322
2323    // Geocoder
2324
2325    @Override
2326    public boolean geocoderIsPresent() {
2327        return mGeocodeProvider != null;
2328    }
2329
2330    @Override
2331    public String getFromLocation(double latitude, double longitude, int maxResults,
2332            GeocoderParams params, List<Address> addrs) {
2333        if (mGeocodeProvider != null) {
2334            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2335                    params, addrs);
2336        }
2337        return null;
2338    }
2339
2340
2341    @Override
2342    public String getFromLocationName(String locationName,
2343            double lowerLeftLatitude, double lowerLeftLongitude,
2344            double upperRightLatitude, double upperRightLongitude, int maxResults,
2345            GeocoderParams params, List<Address> addrs) {
2346
2347        if (mGeocodeProvider != null) {
2348            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2349                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2350                    maxResults, params, addrs);
2351        }
2352        return null;
2353    }
2354
2355    // Mock Providers
2356
2357    private void checkMockPermissionsSafe() {
2358        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2359                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2360        if (!allowMocks) {
2361            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2362        }
2363
2364        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2365                PackageManager.PERMISSION_GRANTED) {
2366            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
2367        }
2368    }
2369
2370    @Override
2371    public void addTestProvider(String name, ProviderProperties properties) {
2372        checkMockPermissionsSafe();
2373
2374        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2375            throw new IllegalArgumentException("Cannot mock the passive location provider");
2376        }
2377
2378        long identity = Binder.clearCallingIdentity();
2379        synchronized (mLock) {
2380            // remove the real provider if we are replacing GPS or network provider
2381            if (LocationManager.GPS_PROVIDER.equals(name)
2382                    || LocationManager.NETWORK_PROVIDER.equals(name)
2383                    || LocationManager.FUSED_PROVIDER.equals(name)) {
2384                LocationProviderInterface p = mProvidersByName.get(name);
2385                if (p != null) {
2386                    removeProviderLocked(p);
2387                }
2388            }
2389            addTestProviderLocked(name, properties);
2390            updateProvidersLocked();
2391        }
2392        Binder.restoreCallingIdentity(identity);
2393    }
2394
2395    private void addTestProviderLocked(String name, ProviderProperties properties) {
2396        if (mProvidersByName.get(name) != null) {
2397            throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2398        }
2399        MockProvider provider = new MockProvider(name, this, properties);
2400        addProviderLocked(provider);
2401        mMockProviders.put(name, provider);
2402        mLastLocation.put(name, null);
2403        mLastLocationCoarseInterval.put(name, null);
2404    }
2405
2406    @Override
2407    public void removeTestProvider(String provider) {
2408        checkMockPermissionsSafe();
2409        synchronized (mLock) {
2410
2411            // These methods can't be called after removing the test provider, so first make sure
2412            // we don't leave anything dangling.
2413            clearTestProviderEnabled(provider);
2414            clearTestProviderLocation(provider);
2415            clearTestProviderStatus(provider);
2416
2417            MockProvider mockProvider = mMockProviders.remove(provider);
2418            if (mockProvider == null) {
2419                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2420            }
2421            long identity = Binder.clearCallingIdentity();
2422            removeProviderLocked(mProvidersByName.get(provider));
2423
2424            // reinstate real provider if available
2425            LocationProviderInterface realProvider = mRealProviders.get(provider);
2426            if (realProvider != null) {
2427                addProviderLocked(realProvider);
2428            }
2429            mLastLocation.put(provider, null);
2430            mLastLocationCoarseInterval.put(provider, null);
2431            updateProvidersLocked();
2432            Binder.restoreCallingIdentity(identity);
2433        }
2434    }
2435
2436    @Override
2437    public void setTestProviderLocation(String provider, Location loc) {
2438        checkMockPermissionsSafe();
2439        synchronized (mLock) {
2440            MockProvider mockProvider = mMockProviders.get(provider);
2441            if (mockProvider == null) {
2442                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2443            }
2444            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2445            long identity = Binder.clearCallingIdentity();
2446            mockProvider.setLocation(loc);
2447            Binder.restoreCallingIdentity(identity);
2448        }
2449    }
2450
2451    @Override
2452    public void clearTestProviderLocation(String provider) {
2453        checkMockPermissionsSafe();
2454        synchronized (mLock) {
2455            MockProvider mockProvider = mMockProviders.get(provider);
2456            if (mockProvider == null) {
2457                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2458            }
2459            mockProvider.clearLocation();
2460        }
2461    }
2462
2463    @Override
2464    public void setTestProviderEnabled(String provider, boolean enabled) {
2465        checkMockPermissionsSafe();
2466        synchronized (mLock) {
2467            MockProvider mockProvider = mMockProviders.get(provider);
2468            if (mockProvider == null) {
2469                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2470            }
2471            long identity = Binder.clearCallingIdentity();
2472            if (enabled) {
2473                mockProvider.enable();
2474                mEnabledProviders.add(provider);
2475                mDisabledProviders.remove(provider);
2476            } else {
2477                mockProvider.disable();
2478                mEnabledProviders.remove(provider);
2479                mDisabledProviders.add(provider);
2480            }
2481            updateProvidersLocked();
2482            Binder.restoreCallingIdentity(identity);
2483        }
2484    }
2485
2486    @Override
2487    public void clearTestProviderEnabled(String provider) {
2488        checkMockPermissionsSafe();
2489        synchronized (mLock) {
2490            MockProvider mockProvider = mMockProviders.get(provider);
2491            if (mockProvider == null) {
2492                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2493            }
2494            long identity = Binder.clearCallingIdentity();
2495            mEnabledProviders.remove(provider);
2496            mDisabledProviders.remove(provider);
2497            updateProvidersLocked();
2498            Binder.restoreCallingIdentity(identity);
2499        }
2500    }
2501
2502    @Override
2503    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2504        checkMockPermissionsSafe();
2505        synchronized (mLock) {
2506            MockProvider mockProvider = mMockProviders.get(provider);
2507            if (mockProvider == null) {
2508                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2509            }
2510            mockProvider.setStatus(status, extras, updateTime);
2511        }
2512    }
2513
2514    @Override
2515    public void clearTestProviderStatus(String provider) {
2516        checkMockPermissionsSafe();
2517        synchronized (mLock) {
2518            MockProvider mockProvider = mMockProviders.get(provider);
2519            if (mockProvider == null) {
2520                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2521            }
2522            mockProvider.clearStatus();
2523        }
2524    }
2525
2526    private void log(String log) {
2527        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2528            Slog.d(TAG, log);
2529        }
2530    }
2531
2532    @Override
2533    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2534        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2535                != PackageManager.PERMISSION_GRANTED) {
2536            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2537                    + Binder.getCallingPid()
2538                    + ", uid=" + Binder.getCallingUid());
2539            return;
2540        }
2541
2542        synchronized (mLock) {
2543            pw.println("Current Location Manager state:");
2544            pw.println("  Location Listeners:");
2545            for (Receiver receiver : mReceivers.values()) {
2546                pw.println("    " + receiver);
2547            }
2548            pw.println("  Active Records by Provider:");
2549            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2550                pw.println("    " + entry.getKey() + ":");
2551                for (UpdateRecord record : entry.getValue()) {
2552                    pw.println("      " + record);
2553                }
2554            }
2555            pw.println("  Historical Records by Provider:");
2556            for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2557                    : mRequestStatistics.statistics.entrySet()) {
2558                PackageProviderKey key = entry.getKey();
2559                PackageStatistics stats = entry.getValue();
2560                pw.println("    " + key.packageName + ": " + key.providerName + ": " + stats);
2561            }
2562            pw.println("  Last Known Locations:");
2563            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2564                String provider = entry.getKey();
2565                Location location = entry.getValue();
2566                pw.println("    " + provider + ": " + location);
2567            }
2568
2569            pw.println("  Last Known Locations Coarse Intervals:");
2570            for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2571                String provider = entry.getKey();
2572                Location location = entry.getValue();
2573                pw.println("    " + provider + ": " + location);
2574            }
2575
2576            mGeofenceManager.dump(pw);
2577
2578            if (mEnabledProviders.size() > 0) {
2579                pw.println("  Enabled Providers:");
2580                for (String i : mEnabledProviders) {
2581                    pw.println("    " + i);
2582                }
2583
2584            }
2585            if (mDisabledProviders.size() > 0) {
2586                pw.println("  Disabled Providers:");
2587                for (String i : mDisabledProviders) {
2588                    pw.println("    " + i);
2589                }
2590            }
2591            pw.append("  ");
2592            mBlacklist.dump(pw);
2593            if (mMockProviders.size() > 0) {
2594                pw.println("  Mock Providers:");
2595                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2596                    i.getValue().dump(pw, "      ");
2597                }
2598            }
2599
2600            pw.append("  fudger: ");
2601            mLocationFudger.dump(fd, pw,  args);
2602
2603            if (args.length > 0 && "short".equals(args[0])) {
2604                return;
2605            }
2606            for (LocationProviderInterface provider: mProviders) {
2607                pw.print(provider.getName() + " Internal State");
2608                if (provider instanceof LocationProviderProxy) {
2609                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
2610                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
2611                }
2612                pw.println(":");
2613                provider.dump(fd, pw, args);
2614            }
2615        }
2616    }
2617}
2618