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