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                changesMade = true;
1152            } else if (!isEnabled && shouldBeEnabled) {
1153                updateProviderListenersLocked(name, true, mCurrentUserId);
1154                changesMade = true;
1155            }
1156        }
1157        if (changesMade) {
1158            mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1159                    UserHandle.ALL);
1160            mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1161                    UserHandle.ALL);
1162        }
1163    }
1164
1165    private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
1166        int listeners = 0;
1167
1168        LocationProviderInterface p = mProvidersByName.get(provider);
1169        if (p == null) return;
1170
1171        ArrayList<Receiver> deadReceivers = null;
1172
1173        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1174        if (records != null) {
1175            final int N = records.size();
1176            for (int i = 0; i < N; i++) {
1177                UpdateRecord record = records.get(i);
1178                if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
1179                    // Sends a notification message to the receiver
1180                    if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1181                        if (deadReceivers == null) {
1182                            deadReceivers = new ArrayList<Receiver>();
1183                        }
1184                        deadReceivers.add(record.mReceiver);
1185                    }
1186                    listeners++;
1187                }
1188            }
1189        }
1190
1191        if (deadReceivers != null) {
1192            for (int i = deadReceivers.size() - 1; i >= 0; i--) {
1193                removeUpdatesLocked(deadReceivers.get(i));
1194            }
1195        }
1196
1197        if (enabled) {
1198            p.enable();
1199            if (listeners > 0) {
1200                applyRequirementsLocked(provider);
1201            }
1202        } else {
1203            p.disable();
1204        }
1205    }
1206
1207    private void applyRequirementsLocked(String provider) {
1208        LocationProviderInterface p = mProvidersByName.get(provider);
1209        if (p == null) return;
1210
1211        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1212        WorkSource worksource = new WorkSource();
1213        ProviderRequest providerRequest = new ProviderRequest();
1214
1215        if (records != null) {
1216            for (UpdateRecord record : records) {
1217                if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
1218                    if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1219                            record.mReceiver.mAllowedResolutionLevel)) {
1220                        LocationRequest locationRequest = record.mRequest;
1221                        providerRequest.locationRequests.add(locationRequest);
1222                        if (locationRequest.getInterval() < providerRequest.interval) {
1223                            providerRequest.reportLocation = true;
1224                            providerRequest.interval = locationRequest.getInterval();
1225                        }
1226                    }
1227                }
1228            }
1229
1230            if (providerRequest.reportLocation) {
1231                // calculate who to blame for power
1232                // This is somewhat arbitrary. We pick a threshold interval
1233                // that is slightly higher that the minimum interval, and
1234                // spread the blame across all applications with a request
1235                // under that threshold.
1236                long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1237                for (UpdateRecord record : records) {
1238                    if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
1239                        LocationRequest locationRequest = record.mRequest;
1240                        if (locationRequest.getInterval() <= thresholdInterval) {
1241                            if (record.mReceiver.mWorkSource != null
1242                                    && record.mReceiver.mWorkSource.size() > 0
1243                                    && record.mReceiver.mWorkSource.getName(0) != null) {
1244                                // Assign blame to another work source.
1245                                // Can only assign blame if the WorkSource contains names.
1246                                worksource.add(record.mReceiver.mWorkSource);
1247                            } else {
1248                                // Assign blame to caller.
1249                                worksource.add(
1250                                        record.mReceiver.mUid,
1251                                        record.mReceiver.mPackageName);
1252                            }
1253                        }
1254                    }
1255                }
1256            }
1257        }
1258
1259        if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1260        p.setRequest(providerRequest, worksource);
1261    }
1262
1263    private class UpdateRecord {
1264        final String mProvider;
1265        final LocationRequest mRequest;
1266        final Receiver mReceiver;
1267        Location mLastFixBroadcast;
1268        long mLastStatusBroadcast;
1269
1270        /**
1271         * Note: must be constructed with lock held.
1272         */
1273        UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
1274            mProvider = provider;
1275            mRequest = request;
1276            mReceiver = receiver;
1277
1278            ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1279            if (records == null) {
1280                records = new ArrayList<UpdateRecord>();
1281                mRecordsByProvider.put(provider, records);
1282            }
1283            if (!records.contains(this)) {
1284                records.add(this);
1285            }
1286        }
1287
1288        /**
1289         * Method to be called when a record will no longer be used.  Calling this multiple times
1290         * must have the same effect as calling it once.
1291         */
1292        void disposeLocked(boolean removeReceiver) {
1293            // remove from mRecordsByProvider
1294            ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1295            if (globalRecords != null) {
1296                globalRecords.remove(this);
1297            }
1298
1299            if (!removeReceiver) return;  // the caller will handle the rest
1300
1301            // remove from Receiver#mUpdateRecords
1302            HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1303            if (receiverRecords != null) {
1304                receiverRecords.remove(this.mProvider);
1305
1306                // and also remove the Receiver if it has no more update records
1307                if (removeReceiver && receiverRecords.size() == 0) {
1308                    removeUpdatesLocked(mReceiver);
1309                }
1310            }
1311        }
1312
1313        @Override
1314        public String toString() {
1315            StringBuilder s = new StringBuilder();
1316            s.append("UpdateRecord[");
1317            s.append(mProvider);
1318            s.append(' ').append(mReceiver.mPackageName).append('(');
1319            s.append(mReceiver.mUid).append(')');
1320            s.append(' ').append(mRequest);
1321            s.append(']');
1322            return s.toString();
1323        }
1324    }
1325
1326    private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
1327            String packageName, WorkSource workSource, boolean hideFromAppOps) {
1328        IBinder binder = listener.asBinder();
1329        Receiver receiver = mReceivers.get(binder);
1330        if (receiver == null) {
1331            receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1332                    hideFromAppOps);
1333            mReceivers.put(binder, receiver);
1334
1335            try {
1336                receiver.getListener().asBinder().linkToDeath(receiver, 0);
1337            } catch (RemoteException e) {
1338                Slog.e(TAG, "linkToDeath failed:", e);
1339                return null;
1340            }
1341        }
1342        return receiver;
1343    }
1344
1345    private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
1346            WorkSource workSource, boolean hideFromAppOps) {
1347        Receiver receiver = mReceivers.get(intent);
1348        if (receiver == null) {
1349            receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1350                    hideFromAppOps);
1351            mReceivers.put(intent, receiver);
1352        }
1353        return receiver;
1354    }
1355
1356    /**
1357     * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1358     * and consistency requirements.
1359     *
1360     * @param request the LocationRequest from which to create a sanitized version
1361     * @return a version of request that meets the given resolution and consistency requirements
1362     * @hide
1363     */
1364    private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1365        LocationRequest sanitizedRequest = new LocationRequest(request);
1366        if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1367            switch (sanitizedRequest.getQuality()) {
1368                case LocationRequest.ACCURACY_FINE:
1369                    sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
1370                    break;
1371                case LocationRequest.POWER_HIGH:
1372                    sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
1373                    break;
1374            }
1375            // throttle
1376            if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1377                sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1378            }
1379            if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1380                sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1381            }
1382        }
1383        // make getFastestInterval() the minimum of interval and fastest interval
1384        if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
1385            request.setFastestInterval(request.getInterval());
1386        }
1387        return sanitizedRequest;
1388    }
1389
1390    private void checkPackageName(String packageName) {
1391        if (packageName == null) {
1392            throw new SecurityException("invalid package name: " + packageName);
1393        }
1394        int uid = Binder.getCallingUid();
1395        String[] packages = mPackageManager.getPackagesForUid(uid);
1396        if (packages == null) {
1397            throw new SecurityException("invalid UID " + uid);
1398        }
1399        for (String pkg : packages) {
1400            if (packageName.equals(pkg)) return;
1401        }
1402        throw new SecurityException("invalid package name: " + packageName);
1403    }
1404
1405    private void checkPendingIntent(PendingIntent intent) {
1406        if (intent == null) {
1407            throw new IllegalArgumentException("invalid pending intent: " + intent);
1408        }
1409    }
1410
1411    private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
1412            int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
1413        if (intent == null && listener == null) {
1414            throw new IllegalArgumentException("need either listener or intent");
1415        } else if (intent != null && listener != null) {
1416            throw new IllegalArgumentException("cannot register both listener and intent");
1417        } else if (intent != null) {
1418            checkPendingIntent(intent);
1419            return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
1420        } else {
1421            return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
1422        }
1423    }
1424
1425    @Override
1426    public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1427            PendingIntent intent, String packageName) {
1428        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1429        checkPackageName(packageName);
1430        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1431        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1432                request.getProvider());
1433        WorkSource workSource = request.getWorkSource();
1434        if (workSource != null && workSource.size() > 0) {
1435            checkDeviceStatsAllowed();
1436        }
1437        boolean hideFromAppOps = request.getHideFromAppOps();
1438        if (hideFromAppOps) {
1439            checkUpdateAppOpsAllowed();
1440        }
1441        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
1442
1443        final int pid = Binder.getCallingPid();
1444        final int uid = Binder.getCallingUid();
1445        // providers may use public location API's, need to clear identity
1446        long identity = Binder.clearCallingIdentity();
1447        try {
1448            // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1449            // a location.
1450            checkLocationAccess(uid, packageName, allowedResolutionLevel);
1451
1452            synchronized (mLock) {
1453                Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
1454                        packageName, workSource, hideFromAppOps);
1455                requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
1456            }
1457        } finally {
1458            Binder.restoreCallingIdentity(identity);
1459        }
1460    }
1461
1462    private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1463            int pid, int uid, String packageName) {
1464        // Figure out the provider. Either its explicitly request (legacy use cases), or
1465        // use the fused provider
1466        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1467        String name = request.getProvider();
1468        if (name == null) {
1469            throw new IllegalArgumentException("provider name must not be null");
1470        }
1471
1472        if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1473                + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
1474        LocationProviderInterface provider = mProvidersByName.get(name);
1475        if (provider == null) {
1476            throw new IllegalArgumentException("provider doesn't exist: " + name);
1477        }
1478
1479        UpdateRecord record = new UpdateRecord(name, request, receiver);
1480        UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1481        if (oldRecord != null) {
1482            oldRecord.disposeLocked(false);
1483        }
1484
1485        boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
1486        if (isProviderEnabled) {
1487            applyRequirementsLocked(name);
1488        } else {
1489            // Notify the listener that updates are currently disabled
1490            receiver.callProviderEnabledLocked(name, false);
1491        }
1492        // Update the monitoring here just in case multiple location requests were added to the
1493        // same receiver (this request may be high power and the initial might not have been).
1494        receiver.updateMonitoring(true);
1495    }
1496
1497    @Override
1498    public void removeUpdates(ILocationListener listener, PendingIntent intent,
1499            String packageName) {
1500        checkPackageName(packageName);
1501
1502        final int pid = Binder.getCallingPid();
1503        final int uid = Binder.getCallingUid();
1504
1505        synchronized (mLock) {
1506            WorkSource workSource = null;
1507            boolean hideFromAppOps = false;
1508            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1509                    packageName, workSource, hideFromAppOps);
1510
1511            // providers may use public location API's, need to clear identity
1512            long identity = Binder.clearCallingIdentity();
1513            try {
1514                removeUpdatesLocked(receiver);
1515            } finally {
1516                Binder.restoreCallingIdentity(identity);
1517            }
1518        }
1519    }
1520
1521    private void removeUpdatesLocked(Receiver receiver) {
1522        if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1523
1524        if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1525            receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1526            synchronized (receiver) {
1527                receiver.clearPendingBroadcastsLocked();
1528            }
1529        }
1530
1531        receiver.updateMonitoring(false);
1532
1533        // Record which providers were associated with this listener
1534        HashSet<String> providers = new HashSet<String>();
1535        HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1536        if (oldRecords != null) {
1537            // Call dispose() on the obsolete update records.
1538            for (UpdateRecord record : oldRecords.values()) {
1539                record.disposeLocked(false);
1540            }
1541            // Accumulate providers
1542            providers.addAll(oldRecords.keySet());
1543        }
1544
1545        // update provider
1546        for (String provider : providers) {
1547            // If provider is already disabled, don't need to do anything
1548            if (!isAllowedByCurrentUserSettingsLocked(provider)) {
1549                continue;
1550            }
1551
1552            applyRequirementsLocked(provider);
1553        }
1554    }
1555
1556    private void applyAllProviderRequirementsLocked() {
1557        for (LocationProviderInterface p : mProviders) {
1558            // If provider is already disabled, don't need to do anything
1559            if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
1560                continue;
1561            }
1562
1563            applyRequirementsLocked(p.getName());
1564        }
1565    }
1566
1567    @Override
1568    public Location getLastLocation(LocationRequest request, String packageName) {
1569        if (D) Log.d(TAG, "getLastLocation: " + request);
1570        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1571        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1572        checkPackageName(packageName);
1573        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1574                request.getProvider());
1575        // no need to sanitize this request, as only the provider name is used
1576
1577        final int uid = Binder.getCallingUid();
1578        final long identity = Binder.clearCallingIdentity();
1579        try {
1580            if (mBlacklist.isBlacklisted(packageName)) {
1581                if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1582                        packageName);
1583                return null;
1584            }
1585
1586            if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1587                if (D) Log.d(TAG, "not returning last loc for no op app: " +
1588                        packageName);
1589                return null;
1590            }
1591
1592            synchronized (mLock) {
1593                // Figure out the provider. Either its explicitly request (deprecated API's),
1594                // or use the fused provider
1595                String name = request.getProvider();
1596                if (name == null) name = LocationManager.FUSED_PROVIDER;
1597                LocationProviderInterface provider = mProvidersByName.get(name);
1598                if (provider == null) return null;
1599
1600                if (!isAllowedByUserSettingsLocked(name, uid)) return null;
1601
1602                Location location;
1603                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1604                    // Make sure that an app with coarse permissions can't get frequent location
1605                    // updates by calling LocationManager.getLastKnownLocation repeatedly.
1606                    location = mLastLocationCoarseInterval.get(name);
1607                } else {
1608                    location = mLastLocation.get(name);
1609                }
1610                if (location == null) {
1611                    return null;
1612                }
1613                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1614                    Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1615                    if (noGPSLocation != null) {
1616                        return new Location(mLocationFudger.getOrCreate(noGPSLocation));
1617                    }
1618                } else {
1619                    return new Location(location);
1620                }
1621            }
1622            return null;
1623        } finally {
1624            Binder.restoreCallingIdentity(identity);
1625        }
1626    }
1627
1628    @Override
1629    public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1630            String packageName) {
1631        if (request == null) request = DEFAULT_LOCATION_REQUEST;
1632        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1633        checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
1634        checkPendingIntent(intent);
1635        checkPackageName(packageName);
1636        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1637                request.getProvider());
1638        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
1639
1640        if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
1641
1642        // geo-fence manager uses the public location API, need to clear identity
1643        int uid = Binder.getCallingUid();
1644        if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1645            // temporary measure until geofences work for secondary users
1646            Log.w(TAG, "proximity alerts are currently available only to the primary user");
1647            return;
1648        }
1649        long identity = Binder.clearCallingIdentity();
1650        try {
1651            mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1652                    uid, packageName);
1653        } finally {
1654            Binder.restoreCallingIdentity(identity);
1655        }
1656    }
1657
1658    @Override
1659    public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1660        checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
1661        checkPendingIntent(intent);
1662        checkPackageName(packageName);
1663
1664        if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1665
1666        // geo-fence manager uses the public location API, need to clear identity
1667        long identity = Binder.clearCallingIdentity();
1668        try {
1669            mGeofenceManager.removeFence(geofence, intent);
1670        } finally {
1671            Binder.restoreCallingIdentity(identity);
1672        }
1673    }
1674
1675
1676    @Override
1677    public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
1678        if (mGpsStatusProvider == null) {
1679            return false;
1680        }
1681        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1682        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1683                LocationManager.GPS_PROVIDER);
1684
1685        final int uid = Binder.getCallingUid();
1686        final long ident = Binder.clearCallingIdentity();
1687        try {
1688            if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
1689                return false;
1690            }
1691        } finally {
1692            Binder.restoreCallingIdentity(ident);
1693        }
1694
1695        try {
1696            mGpsStatusProvider.addGpsStatusListener(listener);
1697        } catch (RemoteException e) {
1698            Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
1699            return false;
1700        }
1701        return true;
1702    }
1703
1704    @Override
1705    public void removeGpsStatusListener(IGpsStatusListener listener) {
1706        synchronized (mLock) {
1707            try {
1708                mGpsStatusProvider.removeGpsStatusListener(listener);
1709            } catch (Exception e) {
1710                Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1711            }
1712        }
1713    }
1714
1715    @Override
1716    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1717        if (provider == null) {
1718            // throw NullPointerException to remain compatible with previous implementation
1719            throw new NullPointerException();
1720        }
1721        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1722                provider);
1723
1724        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1725        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1726                != PackageManager.PERMISSION_GRANTED)) {
1727            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1728        }
1729
1730        synchronized (mLock) {
1731            LocationProviderInterface p = mProvidersByName.get(provider);
1732            if (p == null) return false;
1733
1734            return p.sendExtraCommand(command, extras);
1735        }
1736    }
1737
1738    @Override
1739    public boolean sendNiResponse(int notifId, int userResponse) {
1740        if (Binder.getCallingUid() != Process.myUid()) {
1741            throw new SecurityException(
1742                    "calling sendNiResponse from outside of the system is not allowed");
1743        }
1744        try {
1745            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1746        } catch (RemoteException e) {
1747            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1748            return false;
1749        }
1750    }
1751
1752    /**
1753     * @return null if the provider does not exist
1754     * @throws SecurityException if the provider is not allowed to be
1755     * accessed by the caller
1756     */
1757    @Override
1758    public ProviderProperties getProviderProperties(String provider) {
1759        if (mProvidersByName.get(provider) == null) {
1760          return null;
1761        }
1762
1763        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1764                provider);
1765
1766        LocationProviderInterface p;
1767        synchronized (mLock) {
1768            p = mProvidersByName.get(provider);
1769        }
1770
1771        if (p == null) return null;
1772        return p.getProperties();
1773    }
1774
1775    @Override
1776    public boolean isProviderEnabled(String provider) {
1777        // TODO: remove this check in next release, see b/10696351
1778        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1779                provider);
1780
1781        // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
1782        // so we discourage its use
1783        if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1784
1785        int uid = Binder.getCallingUid();
1786        long identity = Binder.clearCallingIdentity();
1787        try {
1788            synchronized (mLock) {
1789                LocationProviderInterface p = mProvidersByName.get(provider);
1790                if (p == null) return false;
1791
1792                return isAllowedByUserSettingsLocked(provider, uid);
1793            }
1794        } finally {
1795            Binder.restoreCallingIdentity(identity);
1796        }
1797    }
1798
1799    /**
1800     * Returns "true" if the UID belongs to a bound location provider.
1801     *
1802     * @param uid the uid
1803     * @return true if uid belongs to a bound location provider
1804     */
1805    private boolean isUidALocationProvider(int uid) {
1806        if (uid == Process.SYSTEM_UID) {
1807            return true;
1808        }
1809        if (mGeocodeProvider != null) {
1810            if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1811        }
1812        for (LocationProviderProxy proxy : mProxyProviders) {
1813            if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
1814        }
1815        return false;
1816    }
1817
1818    private void checkCallerIsProvider() {
1819        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1820                == PackageManager.PERMISSION_GRANTED) {
1821            return;
1822        }
1823
1824        // Previously we only used the INSTALL_LOCATION_PROVIDER
1825        // check. But that is system or signature
1826        // protection level which is not flexible enough for
1827        // providers installed oustide the system image. So
1828        // also allow providers with a UID matching the
1829        // currently bound package name
1830
1831        if (isUidALocationProvider(Binder.getCallingUid())) {
1832            return;
1833        }
1834
1835        throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1836                "or UID of a currently bound location provider");
1837    }
1838
1839    private boolean doesPackageHaveUid(int uid, String packageName) {
1840        if (packageName == null) {
1841            return false;
1842        }
1843        try {
1844            ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1845            if (appInfo.uid != uid) {
1846                return false;
1847            }
1848        } catch (NameNotFoundException e) {
1849            return false;
1850        }
1851        return true;
1852    }
1853
1854    @Override
1855    public void reportLocation(Location location, boolean passive) {
1856        checkCallerIsProvider();
1857
1858        if (!location.isComplete()) {
1859            Log.w(TAG, "Dropping incomplete location: " + location);
1860            return;
1861        }
1862
1863        mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1864        Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
1865        m.arg1 = (passive ? 1 : 0);
1866        mLocationHandler.sendMessageAtFrontOfQueue(m);
1867    }
1868
1869
1870    private static boolean shouldBroadcastSafe(
1871            Location loc, Location lastLoc, UpdateRecord record, long now) {
1872        // Always broadcast the first update
1873        if (lastLoc == null) {
1874            return true;
1875        }
1876
1877        // Check whether sufficient time has passed
1878        long minTime = record.mRequest.getFastestInterval();
1879        long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
1880                / NANOS_PER_MILLI;
1881        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
1882            return false;
1883        }
1884
1885        // Check whether sufficient distance has been traveled
1886        double minDistance = record.mRequest.getSmallestDisplacement();
1887        if (minDistance > 0.0) {
1888            if (loc.distanceTo(lastLoc) <= minDistance) {
1889                return false;
1890            }
1891        }
1892
1893        // Check whether sufficient number of udpates is left
1894        if (record.mRequest.getNumUpdates() <= 0) {
1895            return false;
1896        }
1897
1898        // Check whether the expiry date has passed
1899        if (record.mRequest.getExpireAt() < now) {
1900            return false;
1901        }
1902
1903        return true;
1904    }
1905
1906    private void handleLocationChangedLocked(Location location, boolean passive) {
1907        if (D) Log.d(TAG, "incoming location: " + location);
1908
1909        long now = SystemClock.elapsedRealtime();
1910        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
1911
1912        // Skip if the provider is unknown.
1913        LocationProviderInterface p = mProvidersByName.get(provider);
1914        if (p == null) return;
1915
1916        // Update last known locations
1917        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1918        Location lastNoGPSLocation = null;
1919        Location lastLocation = mLastLocation.get(provider);
1920        if (lastLocation == null) {
1921            lastLocation = new Location(provider);
1922            mLastLocation.put(provider, lastLocation);
1923        } else {
1924            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1925            if (noGPSLocation == null && lastNoGPSLocation != null) {
1926                // New location has no no-GPS location: adopt last no-GPS location. This is set
1927                // directly into location because we do not want to notify COARSE clients.
1928                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1929            }
1930        }
1931        lastLocation.set(location);
1932
1933        // Update last known coarse interval location if enough time has passed.
1934        Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
1935        if (lastLocationCoarseInterval == null) {
1936            lastLocationCoarseInterval = new Location(location);
1937            mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
1938        }
1939        long timeDiffNanos = location.getElapsedRealtimeNanos()
1940                - lastLocationCoarseInterval.getElapsedRealtimeNanos();
1941        if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
1942            lastLocationCoarseInterval.set(location);
1943        }
1944        // Don't ever return a coarse location that is more recent than the allowed update
1945        // interval (i.e. don't allow an app to keep registering and unregistering for
1946        // location updates to overcome the minimum interval).
1947        noGPSLocation =
1948                lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1949
1950        // Skip if there are no UpdateRecords for this provider.
1951        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1952        if (records == null || records.size() == 0) return;
1953
1954        // Fetch coarse location
1955        Location coarseLocation = null;
1956        if (noGPSLocation != null) {
1957            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1958        }
1959
1960        // Fetch latest status update time
1961        long newStatusUpdateTime = p.getStatusUpdateTime();
1962
1963       // Get latest status
1964        Bundle extras = new Bundle();
1965        int status = p.getStatus(extras);
1966
1967        ArrayList<Receiver> deadReceivers = null;
1968        ArrayList<UpdateRecord> deadUpdateRecords = null;
1969
1970        // Broadcast location or status to all listeners
1971        for (UpdateRecord r : records) {
1972            Receiver receiver = r.mReceiver;
1973            boolean receiverDead = false;
1974
1975            int receiverUserId = UserHandle.getUserId(receiver.mUid);
1976            if (receiverUserId != mCurrentUserId && !isUidALocationProvider(receiver.mUid)) {
1977                if (D) {
1978                    Log.d(TAG, "skipping loc update for background user " + receiverUserId +
1979                            " (current user: " + mCurrentUserId + ", app: " +
1980                            receiver.mPackageName + ")");
1981                }
1982                continue;
1983            }
1984
1985            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1986                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1987                        receiver.mPackageName);
1988                continue;
1989            }
1990
1991            if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
1992                    receiver.mAllowedResolutionLevel)) {
1993                if (D) Log.d(TAG, "skipping loc update for no op app: " +
1994                        receiver.mPackageName);
1995                continue;
1996            }
1997
1998            Location notifyLocation = null;
1999            if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2000                notifyLocation = coarseLocation;  // use coarse location
2001            } else {
2002                notifyLocation = lastLocation;  // use fine location
2003            }
2004            if (notifyLocation != null) {
2005                Location lastLoc = r.mLastFixBroadcast;
2006                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
2007                    if (lastLoc == null) {
2008                        lastLoc = new Location(notifyLocation);
2009                        r.mLastFixBroadcast = lastLoc;
2010                    } else {
2011                        lastLoc.set(notifyLocation);
2012                    }
2013                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
2014                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2015                        receiverDead = true;
2016                    }
2017                    r.mRequest.decrementNumUpdates();
2018                }
2019            }
2020
2021            long prevStatusUpdateTime = r.mLastStatusBroadcast;
2022            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
2023                    (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
2024
2025                r.mLastStatusBroadcast = newStatusUpdateTime;
2026                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
2027                    receiverDead = true;
2028                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
2029                }
2030            }
2031
2032            // track expired records
2033            if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
2034                if (deadUpdateRecords == null) {
2035                    deadUpdateRecords = new ArrayList<UpdateRecord>();
2036                }
2037                deadUpdateRecords.add(r);
2038            }
2039            // track dead receivers
2040            if (receiverDead) {
2041                if (deadReceivers == null) {
2042                    deadReceivers = new ArrayList<Receiver>();
2043                }
2044                if (!deadReceivers.contains(receiver)) {
2045                    deadReceivers.add(receiver);
2046                }
2047            }
2048        }
2049
2050        // remove dead records and receivers outside the loop
2051        if (deadReceivers != null) {
2052            for (Receiver receiver : deadReceivers) {
2053                removeUpdatesLocked(receiver);
2054            }
2055        }
2056        if (deadUpdateRecords != null) {
2057            for (UpdateRecord r : deadUpdateRecords) {
2058                r.disposeLocked(true);
2059            }
2060            applyRequirementsLocked(provider);
2061        }
2062    }
2063
2064    private class LocationWorkerHandler extends Handler {
2065        public LocationWorkerHandler(Looper looper) {
2066            super(looper, null, true);
2067        }
2068
2069        @Override
2070        public void handleMessage(Message msg) {
2071            switch (msg.what) {
2072                case MSG_LOCATION_CHANGED:
2073                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2074                    break;
2075            }
2076        }
2077    }
2078
2079    private boolean isMockProvider(String provider) {
2080        synchronized (mLock) {
2081            return mMockProviders.containsKey(provider);
2082        }
2083    }
2084
2085    private void handleLocationChanged(Location location, boolean passive) {
2086        // create a working copy of the incoming Location so that the service can modify it without
2087        // disturbing the caller's copy
2088        Location myLocation = new Location(location);
2089        String provider = myLocation.getProvider();
2090
2091        // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2092        // bit if location did not come from a mock provider because passive/fused providers can
2093        // forward locations from mock providers, and should not grant them legitimacy in doing so.
2094        if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2095            myLocation.setIsFromMockProvider(true);
2096        }
2097
2098        synchronized (mLock) {
2099            if (isAllowedByCurrentUserSettingsLocked(provider)) {
2100                if (!passive) {
2101                    // notify passive provider of the new location
2102                    mPassiveProvider.updateLocation(myLocation);
2103                }
2104                handleLocationChangedLocked(myLocation, passive);
2105            }
2106        }
2107    }
2108
2109    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2110        @Override
2111        public void onPackageDisappeared(String packageName, int reason) {
2112            // remove all receivers associated with this package name
2113            synchronized (mLock) {
2114                ArrayList<Receiver> deadReceivers = null;
2115
2116                for (Receiver receiver : mReceivers.values()) {
2117                    if (receiver.mPackageName.equals(packageName)) {
2118                        if (deadReceivers == null) {
2119                            deadReceivers = new ArrayList<Receiver>();
2120                        }
2121                        deadReceivers.add(receiver);
2122                    }
2123                }
2124
2125                // perform removal outside of mReceivers loop
2126                if (deadReceivers != null) {
2127                    for (Receiver receiver : deadReceivers) {
2128                        removeUpdatesLocked(receiver);
2129                    }
2130                }
2131            }
2132        }
2133    };
2134
2135    // Geocoder
2136
2137    @Override
2138    public boolean geocoderIsPresent() {
2139        return mGeocodeProvider != null;
2140    }
2141
2142    @Override
2143    public String getFromLocation(double latitude, double longitude, int maxResults,
2144            GeocoderParams params, List<Address> addrs) {
2145        if (mGeocodeProvider != null) {
2146            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2147                    params, addrs);
2148        }
2149        return null;
2150    }
2151
2152
2153    @Override
2154    public String getFromLocationName(String locationName,
2155            double lowerLeftLatitude, double lowerLeftLongitude,
2156            double upperRightLatitude, double upperRightLongitude, int maxResults,
2157            GeocoderParams params, List<Address> addrs) {
2158
2159        if (mGeocodeProvider != null) {
2160            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2161                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2162                    maxResults, params, addrs);
2163        }
2164        return null;
2165    }
2166
2167    // Mock Providers
2168
2169    private void checkMockPermissionsSafe() {
2170        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2171                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2172        if (!allowMocks) {
2173            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2174        }
2175
2176        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2177            PackageManager.PERMISSION_GRANTED) {
2178            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
2179        }
2180    }
2181
2182    @Override
2183    public void addTestProvider(String name, ProviderProperties properties) {
2184        checkMockPermissionsSafe();
2185
2186        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2187            throw new IllegalArgumentException("Cannot mock the passive location provider");
2188        }
2189
2190        long identity = Binder.clearCallingIdentity();
2191        synchronized (mLock) {
2192            MockProvider provider = new MockProvider(name, this, properties);
2193            // remove the real provider if we are replacing GPS or network provider
2194            if (LocationManager.GPS_PROVIDER.equals(name)
2195                    || LocationManager.NETWORK_PROVIDER.equals(name)
2196                    || LocationManager.FUSED_PROVIDER.equals(name)) {
2197                LocationProviderInterface p = mProvidersByName.get(name);
2198                if (p != null) {
2199                    removeProviderLocked(p);
2200                }
2201            }
2202            if (mProvidersByName.get(name) != null) {
2203                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2204            }
2205            addProviderLocked(provider);
2206            mMockProviders.put(name, provider);
2207            mLastLocation.put(name, null);
2208            mLastLocationCoarseInterval.put(name, null);
2209            updateProvidersLocked();
2210        }
2211        Binder.restoreCallingIdentity(identity);
2212    }
2213
2214    @Override
2215    public void removeTestProvider(String provider) {
2216        checkMockPermissionsSafe();
2217        synchronized (mLock) {
2218            MockProvider mockProvider = mMockProviders.remove(provider);
2219            if (mockProvider == null) {
2220                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2221            }
2222            long identity = Binder.clearCallingIdentity();
2223            removeProviderLocked(mProvidersByName.get(provider));
2224
2225            // reinstate real provider if available
2226            LocationProviderInterface realProvider = mRealProviders.get(provider);
2227            if (realProvider != null) {
2228                addProviderLocked(realProvider);
2229            }
2230            mLastLocation.put(provider, null);
2231            mLastLocationCoarseInterval.put(provider, null);
2232            updateProvidersLocked();
2233            Binder.restoreCallingIdentity(identity);
2234        }
2235    }
2236
2237    @Override
2238    public void setTestProviderLocation(String provider, Location loc) {
2239        checkMockPermissionsSafe();
2240        synchronized (mLock) {
2241            MockProvider mockProvider = mMockProviders.get(provider);
2242            if (mockProvider == null) {
2243                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2244            }
2245            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2246            long identity = Binder.clearCallingIdentity();
2247            mockProvider.setLocation(loc);
2248            Binder.restoreCallingIdentity(identity);
2249        }
2250    }
2251
2252    @Override
2253    public void clearTestProviderLocation(String provider) {
2254        checkMockPermissionsSafe();
2255        synchronized (mLock) {
2256            MockProvider mockProvider = mMockProviders.get(provider);
2257            if (mockProvider == null) {
2258                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2259            }
2260            mockProvider.clearLocation();
2261        }
2262    }
2263
2264    @Override
2265    public void setTestProviderEnabled(String provider, boolean enabled) {
2266        checkMockPermissionsSafe();
2267        synchronized (mLock) {
2268            MockProvider mockProvider = mMockProviders.get(provider);
2269            if (mockProvider == null) {
2270                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2271            }
2272            long identity = Binder.clearCallingIdentity();
2273            if (enabled) {
2274                mockProvider.enable();
2275                mEnabledProviders.add(provider);
2276                mDisabledProviders.remove(provider);
2277            } else {
2278                mockProvider.disable();
2279                mEnabledProviders.remove(provider);
2280                mDisabledProviders.add(provider);
2281            }
2282            updateProvidersLocked();
2283            Binder.restoreCallingIdentity(identity);
2284        }
2285    }
2286
2287    @Override
2288    public void clearTestProviderEnabled(String provider) {
2289        checkMockPermissionsSafe();
2290        synchronized (mLock) {
2291            MockProvider mockProvider = mMockProviders.get(provider);
2292            if (mockProvider == null) {
2293                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2294            }
2295            long identity = Binder.clearCallingIdentity();
2296            mEnabledProviders.remove(provider);
2297            mDisabledProviders.remove(provider);
2298            updateProvidersLocked();
2299            Binder.restoreCallingIdentity(identity);
2300        }
2301    }
2302
2303    @Override
2304    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2305        checkMockPermissionsSafe();
2306        synchronized (mLock) {
2307            MockProvider mockProvider = mMockProviders.get(provider);
2308            if (mockProvider == null) {
2309                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2310            }
2311            mockProvider.setStatus(status, extras, updateTime);
2312        }
2313    }
2314
2315    @Override
2316    public void clearTestProviderStatus(String provider) {
2317        checkMockPermissionsSafe();
2318        synchronized (mLock) {
2319            MockProvider mockProvider = mMockProviders.get(provider);
2320            if (mockProvider == null) {
2321                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2322            }
2323            mockProvider.clearStatus();
2324        }
2325    }
2326
2327    private void log(String log) {
2328        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2329            Slog.d(TAG, log);
2330        }
2331    }
2332
2333    @Override
2334    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2335        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2336                != PackageManager.PERMISSION_GRANTED) {
2337            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2338                    + Binder.getCallingPid()
2339                    + ", uid=" + Binder.getCallingUid());
2340            return;
2341        }
2342
2343        synchronized (mLock) {
2344            pw.println("Current Location Manager state:");
2345            pw.println("  Location Listeners:");
2346            for (Receiver receiver : mReceivers.values()) {
2347                pw.println("    " + receiver);
2348            }
2349            pw.println("  Records by Provider:");
2350            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2351                pw.println("    " + entry.getKey() + ":");
2352                for (UpdateRecord record : entry.getValue()) {
2353                    pw.println("      " + record);
2354                }
2355            }
2356            pw.println("  Last Known Locations:");
2357            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2358                String provider = entry.getKey();
2359                Location location = entry.getValue();
2360                pw.println("    " + provider + ": " + location);
2361            }
2362
2363            pw.println("  Last Known Locations Coarse Intervals:");
2364            for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2365                String provider = entry.getKey();
2366                Location location = entry.getValue();
2367                pw.println("    " + provider + ": " + location);
2368            }
2369
2370            mGeofenceManager.dump(pw);
2371
2372            if (mEnabledProviders.size() > 0) {
2373                pw.println("  Enabled Providers:");
2374                for (String i : mEnabledProviders) {
2375                    pw.println("    " + i);
2376                }
2377
2378            }
2379            if (mDisabledProviders.size() > 0) {
2380                pw.println("  Disabled Providers:");
2381                for (String i : mDisabledProviders) {
2382                    pw.println("    " + i);
2383                }
2384            }
2385            pw.append("  ");
2386            mBlacklist.dump(pw);
2387            if (mMockProviders.size() > 0) {
2388                pw.println("  Mock Providers:");
2389                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2390                    i.getValue().dump(pw, "      ");
2391                }
2392            }
2393
2394            pw.append("  fudger: ");
2395            mLocationFudger.dump(fd, pw,  args);
2396
2397            if (args.length > 0 && "short".equals(args[0])) {
2398                return;
2399            }
2400            for (LocationProviderInterface provider: mProviders) {
2401                pw.print(provider.getName() + " Internal State");
2402                if (provider instanceof LocationProviderProxy) {
2403                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
2404                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
2405                }
2406                pw.println(":");
2407                provider.dump(fd, pw, args);
2408            }
2409        }
2410    }
2411}
2412