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