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