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