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