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