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