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