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