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