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