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