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(new Bundle(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(new Location(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, new Location(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        if (D) Log.d(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        if (D) 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 new Location(mLocationFudger.getOrCreate(noGPSLocation));
1327                    }
1328                } else {
1329                    return new Location(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            applyRequirementsLocked(provider);
1714        }
1715    }
1716
1717    private class LocationWorkerHandler extends Handler {
1718        @Override
1719        public void handleMessage(Message msg) {
1720            switch (msg.what) {
1721                case MSG_LOCATION_CHANGED:
1722                    handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1723                    break;
1724            }
1725        }
1726    }
1727
1728    private void handleLocationChanged(Location location, boolean passive) {
1729        String provider = location.getProvider();
1730
1731        if (!passive) {
1732            // notify passive provider of the new location
1733            mPassiveProvider.updateLocation(location);
1734        }
1735
1736        synchronized (mLock) {
1737            if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
1738                handleLocationChangedLocked(location, passive);
1739            }
1740        }
1741    }
1742
1743    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1744        @Override
1745        public void onPackageDisappeared(String packageName, int reason) {
1746            // remove all receivers associated with this package name
1747            synchronized (mLock) {
1748                ArrayList<Receiver> deadReceivers = null;
1749
1750                for (Receiver receiver : mReceivers.values()) {
1751                    if (receiver.mPackageName.equals(packageName)) {
1752                        if (deadReceivers == null) {
1753                            deadReceivers = new ArrayList<Receiver>();
1754                        }
1755                        deadReceivers.add(receiver);
1756                    }
1757                }
1758
1759                // perform removal outside of mReceivers loop
1760                if (deadReceivers != null) {
1761                    for (Receiver receiver : deadReceivers) {
1762                        removeUpdatesLocked(receiver);
1763                    }
1764                }
1765            }
1766        }
1767    };
1768
1769    // Wake locks
1770
1771    private void incrementPendingBroadcasts() {
1772        synchronized (mWakeLock) {
1773            if (mPendingBroadcasts++ == 0) {
1774                try {
1775                    mWakeLock.acquire();
1776                    log("Acquired wakelock");
1777                } catch (Exception e) {
1778                    // This is to catch a runtime exception thrown when we try to release an
1779                    // already released lock.
1780                    Slog.e(TAG, "exception in acquireWakeLock()", e);
1781                }
1782            }
1783        }
1784    }
1785
1786    private void decrementPendingBroadcasts() {
1787        synchronized (mWakeLock) {
1788            if (--mPendingBroadcasts == 0) {
1789                try {
1790                    // Release wake lock
1791                    if (mWakeLock.isHeld()) {
1792                        mWakeLock.release();
1793                        log("Released wakelock");
1794                    } else {
1795                        log("Can't release wakelock again!");
1796                    }
1797                } catch (Exception e) {
1798                    // This is to catch a runtime exception thrown when we try to release an
1799                    // already released lock.
1800                    Slog.e(TAG, "exception in releaseWakeLock()", e);
1801                }
1802            }
1803        }
1804    }
1805
1806    // Geocoder
1807
1808    @Override
1809    public boolean geocoderIsPresent() {
1810        return mGeocodeProvider != null;
1811    }
1812
1813    @Override
1814    public String getFromLocation(double latitude, double longitude, int maxResults,
1815            GeocoderParams params, List<Address> addrs) {
1816        if (mGeocodeProvider != null) {
1817            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1818                    params, addrs);
1819        }
1820        return null;
1821    }
1822
1823
1824    @Override
1825    public String getFromLocationName(String locationName,
1826            double lowerLeftLatitude, double lowerLeftLongitude,
1827            double upperRightLatitude, double upperRightLongitude, int maxResults,
1828            GeocoderParams params, List<Address> addrs) {
1829
1830        if (mGeocodeProvider != null) {
1831            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1832                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1833                    maxResults, params, addrs);
1834        }
1835        return null;
1836    }
1837
1838    // Mock Providers
1839
1840    private void checkMockPermissionsSafe() {
1841        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1842                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1843        if (!allowMocks) {
1844            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1845        }
1846
1847        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1848            PackageManager.PERMISSION_GRANTED) {
1849            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1850        }
1851    }
1852
1853    @Override
1854    public void addTestProvider(String name, ProviderProperties properties) {
1855        checkMockPermissionsSafe();
1856
1857        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1858            throw new IllegalArgumentException("Cannot mock the passive location provider");
1859        }
1860
1861        long identity = Binder.clearCallingIdentity();
1862        synchronized (mLock) {
1863            MockProvider provider = new MockProvider(name, this, properties);
1864            // remove the real provider if we are replacing GPS or network provider
1865            if (LocationManager.GPS_PROVIDER.equals(name)
1866                    || LocationManager.NETWORK_PROVIDER.equals(name)
1867                    || LocationManager.FUSED_PROVIDER.equals(name)) {
1868                LocationProviderInterface p = mProvidersByName.get(name);
1869                if (p != null) {
1870                    removeProviderLocked(p);
1871                }
1872            }
1873            if (mProvidersByName.get(name) != null) {
1874                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1875            }
1876            addProviderLocked(provider);
1877            mMockProviders.put(name, provider);
1878            mLastLocation.put(name, null);
1879            updateProvidersLocked();
1880        }
1881        Binder.restoreCallingIdentity(identity);
1882    }
1883
1884    @Override
1885    public void removeTestProvider(String provider) {
1886        checkMockPermissionsSafe();
1887        synchronized (mLock) {
1888            MockProvider mockProvider = mMockProviders.get(provider);
1889            if (mockProvider == null) {
1890                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1891            }
1892            long identity = Binder.clearCallingIdentity();
1893            removeProviderLocked(mProvidersByName.get(provider));
1894            mMockProviders.remove(mockProvider);
1895
1896            // reinstate real provider if available
1897            LocationProviderInterface realProvider = mRealProviders.get(provider);
1898            if (realProvider != null) {
1899                addProviderLocked(realProvider);
1900            }
1901            mLastLocation.put(provider, null);
1902            updateProvidersLocked();
1903            Binder.restoreCallingIdentity(identity);
1904        }
1905    }
1906
1907    @Override
1908    public void setTestProviderLocation(String provider, Location loc) {
1909        checkMockPermissionsSafe();
1910        synchronized (mLock) {
1911            MockProvider mockProvider = mMockProviders.get(provider);
1912            if (mockProvider == null) {
1913                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1914            }
1915            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1916            long identity = Binder.clearCallingIdentity();
1917            mockProvider.setLocation(loc);
1918            Binder.restoreCallingIdentity(identity);
1919        }
1920    }
1921
1922    @Override
1923    public void clearTestProviderLocation(String provider) {
1924        checkMockPermissionsSafe();
1925        synchronized (mLock) {
1926            MockProvider mockProvider = mMockProviders.get(provider);
1927            if (mockProvider == null) {
1928                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1929            }
1930            mockProvider.clearLocation();
1931        }
1932    }
1933
1934    @Override
1935    public void setTestProviderEnabled(String provider, boolean enabled) {
1936        checkMockPermissionsSafe();
1937        synchronized (mLock) {
1938            MockProvider mockProvider = mMockProviders.get(provider);
1939            if (mockProvider == null) {
1940                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1941            }
1942            long identity = Binder.clearCallingIdentity();
1943            if (enabled) {
1944                mockProvider.enable();
1945                mEnabledProviders.add(provider);
1946                mDisabledProviders.remove(provider);
1947            } else {
1948                mockProvider.disable();
1949                mEnabledProviders.remove(provider);
1950                mDisabledProviders.add(provider);
1951            }
1952            updateProvidersLocked();
1953            Binder.restoreCallingIdentity(identity);
1954        }
1955    }
1956
1957    @Override
1958    public void clearTestProviderEnabled(String provider) {
1959        checkMockPermissionsSafe();
1960        synchronized (mLock) {
1961            MockProvider mockProvider = mMockProviders.get(provider);
1962            if (mockProvider == null) {
1963                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1964            }
1965            long identity = Binder.clearCallingIdentity();
1966            mEnabledProviders.remove(provider);
1967            mDisabledProviders.remove(provider);
1968            updateProvidersLocked();
1969            Binder.restoreCallingIdentity(identity);
1970        }
1971    }
1972
1973    @Override
1974    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1975        checkMockPermissionsSafe();
1976        synchronized (mLock) {
1977            MockProvider mockProvider = mMockProviders.get(provider);
1978            if (mockProvider == null) {
1979                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1980            }
1981            mockProvider.setStatus(status, extras, updateTime);
1982        }
1983    }
1984
1985    @Override
1986    public void clearTestProviderStatus(String provider) {
1987        checkMockPermissionsSafe();
1988        synchronized (mLock) {
1989            MockProvider mockProvider = mMockProviders.get(provider);
1990            if (mockProvider == null) {
1991                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1992            }
1993            mockProvider.clearStatus();
1994        }
1995    }
1996
1997    private void log(String log) {
1998        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1999            Slog.d(TAG, log);
2000        }
2001    }
2002
2003    @Override
2004    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2005        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2006                != PackageManager.PERMISSION_GRANTED) {
2007            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2008                    + Binder.getCallingPid()
2009                    + ", uid=" + Binder.getCallingUid());
2010            return;
2011        }
2012
2013        synchronized (mLock) {
2014            pw.println("Current Location Manager state:");
2015            pw.println("  Location Listeners:");
2016            for (Receiver receiver : mReceivers.values()) {
2017                pw.println("    " + receiver);
2018            }
2019            pw.println("  Records by Provider:");
2020            for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2021                pw.println("    " + entry.getKey() + ":");
2022                for (UpdateRecord record : entry.getValue()) {
2023                    pw.println("      " + record);
2024                }
2025            }
2026            pw.println("  Last Known Locations:");
2027            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2028                String provider = entry.getKey();
2029                Location location = entry.getValue();
2030                pw.println("    " + provider + ": " + location);
2031            }
2032
2033            mGeofenceManager.dump(pw);
2034
2035            if (mEnabledProviders.size() > 0) {
2036                pw.println("  Enabled Providers:");
2037                for (String i : mEnabledProviders) {
2038                    pw.println("    " + i);
2039                }
2040
2041            }
2042            if (mDisabledProviders.size() > 0) {
2043                pw.println("  Disabled Providers:");
2044                for (String i : mDisabledProviders) {
2045                    pw.println("    " + i);
2046                }
2047            }
2048            pw.append("  ");
2049            mBlacklist.dump(pw);
2050            if (mMockProviders.size() > 0) {
2051                pw.println("  Mock Providers:");
2052                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2053                    i.getValue().dump(pw, "      ");
2054                }
2055            }
2056
2057            pw.append("  fudger: ");
2058            mLocationFudger.dump(fd, pw,  args);
2059
2060            if (args.length > 0 && "short".equals(args[0])) {
2061                return;
2062            }
2063            for (LocationProviderInterface provider: mProviders) {
2064                pw.print(provider.getName() + " Internal State");
2065                if (provider instanceof LocationProviderProxy) {
2066                    LocationProviderProxy proxy = (LocationProviderProxy) provider;
2067                    pw.print(" (" + proxy.getConnectedPackageName() + ")");
2068                }
2069                pw.println(":");
2070                provider.dump(fd, pw, args);
2071            }
2072        }
2073    }
2074}
2075