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