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