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