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