LocationManagerService.java revision 821bd8081a3a02de946af7a5c2ab52cdc3e48c4e
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.Activity;
20import android.app.PendingIntent;
21import android.content.BroadcastReceiver;
22import android.content.ContentQueryMap;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.pm.PackageManager;
28import android.content.pm.ResolveInfo;
29import android.content.res.Resources;
30import android.database.Cursor;
31import android.location.Address;
32import android.location.Criteria;
33import android.location.GeocoderParams;
34import android.location.IGpsStatusListener;
35import android.location.IGpsStatusProvider;
36import android.location.ILocationListener;
37import android.location.ILocationManager;
38import android.location.INetInitiatedListener;
39import android.location.Location;
40import android.location.LocationManager;
41import android.location.LocationProvider;
42import android.net.ConnectivityManager;
43import android.net.NetworkInfo;
44import android.os.Binder;
45import android.os.Bundle;
46import android.os.Handler;
47import android.os.IBinder;
48import android.os.Looper;
49import android.os.Message;
50import android.os.PowerManager;
51import android.os.Process;
52import android.os.RemoteException;
53import android.os.WorkSource;
54import android.provider.Settings;
55import android.provider.Settings.NameValueTable;
56import android.util.Log;
57import android.util.Slog;
58import android.util.PrintWriterPrinter;
59
60import com.android.internal.content.PackageMonitor;
61
62import com.android.server.location.GeocoderProxy;
63import com.android.server.location.GeofenceManager;
64import com.android.server.location.GpsLocationProvider;
65import com.android.server.location.LocationProviderInterface;
66import com.android.server.location.LocationProviderProxy;
67import com.android.server.location.MockProvider;
68import com.android.server.location.PassiveProvider;
69
70import java.io.FileDescriptor;
71import java.io.PrintWriter;
72import java.util.ArrayList;
73import java.util.Collections;
74import java.util.Comparator;
75import java.util.HashMap;
76import java.util.HashSet;
77import java.util.List;
78import java.util.Map;
79import java.util.Observable;
80import java.util.Observer;
81import java.util.Set;
82
83/**
84 * The service class that manages LocationProviders and issues location
85 * updates and alerts.
86 *
87 * {@hide}
88 */
89public class LocationManagerService extends ILocationManager.Stub implements Runnable {
90    private static final String TAG = "LocationManagerService";
91    private static final boolean LOCAL_LOGV = false;
92
93    private static final String ACCESS_FINE_LOCATION =
94        android.Manifest.permission.ACCESS_FINE_LOCATION;
95    private static final String ACCESS_COARSE_LOCATION =
96        android.Manifest.permission.ACCESS_COARSE_LOCATION;
97    private static final String ACCESS_MOCK_LOCATION =
98        android.Manifest.permission.ACCESS_MOCK_LOCATION;
99    private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
100        android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
101    private static final String INSTALL_LOCATION_PROVIDER =
102        android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
103
104    // Location Providers may sometimes deliver location updates
105    // slightly faster that requested - provide grace period so
106    // we don't unnecessarily filter events that are otherwise on
107    // time
108    private static final int MAX_PROVIDER_SCHEDULING_JITTER = 100;
109
110    // Set of providers that are explicitly enabled
111    private final Set<String> mEnabledProviders = new HashSet<String>();
112
113    // Set of providers that are explicitly disabled
114    private final Set<String> mDisabledProviders = new HashSet<String>();
115
116    // Locations, status values, and extras for mock providers
117    private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>();
118
119    private static boolean sProvidersLoaded = false;
120
121    private final Context mContext;
122    private PackageManager mPackageManager;  // final after initialize()
123    private String mNetworkLocationProviderPackageName;  // only used on handler thread
124    private String mGeocodeProviderPackageName;  // only used on handler thread
125    private GeocoderProxy mGeocodeProvider;
126    private IGpsStatusProvider mGpsStatusProvider;
127    private INetInitiatedListener mNetInitiatedListener;
128    private LocationWorkerHandler mLocationHandler;
129
130    // Cache the real providers for use in addTestProvider() and removeTestProvider()
131     LocationProviderProxy mNetworkLocationProvider;
132     LocationProviderInterface mGpsLocationProvider;
133
134    // Handler messages
135    private static final int MESSAGE_LOCATION_CHANGED = 1;
136    private static final int MESSAGE_PACKAGE_UPDATED = 2;
137
138    // wakelock variables
139    private final static String WAKELOCK_KEY = "LocationManagerService";
140    private PowerManager.WakeLock mWakeLock = null;
141    private int mPendingBroadcasts;
142
143    /**
144     * List of all receivers.
145     */
146    private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
147
148
149    /**
150     * List of location providers.
151     */
152    private final ArrayList<LocationProviderInterface> mProviders =
153        new ArrayList<LocationProviderInterface>();
154    private final HashMap<String, LocationProviderInterface> mProvidersByName
155        = new HashMap<String, LocationProviderInterface>();
156
157    /**
158     * Object used internally for synchronization
159     */
160    private final Object mLock = new Object();
161
162    /**
163     * Mapping from provider name to all its UpdateRecords
164     */
165    private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
166        new HashMap<String,ArrayList<UpdateRecord>>();
167
168    /**
169     * Temporary filled in when computing min time for a provider.  Access is
170     * protected by global lock mLock.
171     */
172    private final WorkSource mTmpWorkSource = new WorkSource();
173
174    GeofenceManager mGeofenceManager;
175
176    // Last known location for each provider
177    private HashMap<String,Location> mLastKnownLocation =
178        new HashMap<String,Location>();
179
180    private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
181
182    // for Settings change notification
183    private ContentQueryMap mSettings;
184
185    /**
186     * A wrapper class holding either an ILocationListener or a PendingIntent to receive
187     * location updates.
188     */
189    private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
190        final ILocationListener mListener;
191        final PendingIntent mPendingIntent;
192        final Object mKey;
193        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
194
195        int mPendingBroadcasts;
196        String mRequiredPermissions;
197
198        Receiver(ILocationListener listener) {
199            mListener = listener;
200            mPendingIntent = null;
201            mKey = listener.asBinder();
202        }
203
204        Receiver(PendingIntent intent) {
205            mPendingIntent = intent;
206            mListener = null;
207            mKey = intent;
208        }
209
210        @Override
211        public boolean equals(Object otherObj) {
212            if (otherObj instanceof Receiver) {
213                return mKey.equals(
214                        ((Receiver)otherObj).mKey);
215            }
216            return false;
217        }
218
219        @Override
220        public int hashCode() {
221            return mKey.hashCode();
222        }
223
224        @Override
225        public String toString() {
226            String result;
227            if (mListener != null) {
228                result = "Receiver{"
229                        + Integer.toHexString(System.identityHashCode(this))
230                        + " Listener " + mKey + "}";
231            } else {
232                result = "Receiver{"
233                        + Integer.toHexString(System.identityHashCode(this))
234                        + " Intent " + mKey + "}";
235            }
236            result += "mUpdateRecords: " + mUpdateRecords;
237            return result;
238        }
239
240        public boolean isListener() {
241            return mListener != null;
242        }
243
244        public boolean isPendingIntent() {
245            return mPendingIntent != null;
246        }
247
248        public ILocationListener getListener() {
249            if (mListener != null) {
250                return mListener;
251            }
252            throw new IllegalStateException("Request for non-existent listener");
253        }
254
255        public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
256            if (mListener != null) {
257                try {
258                    synchronized (this) {
259                        // synchronize to ensure incrementPendingBroadcastsLocked()
260                        // is called before decrementPendingBroadcasts()
261                        mListener.onStatusChanged(provider, status, extras);
262                        // call this after broadcasting so we do not increment
263                        // if we throw an exeption.
264                        incrementPendingBroadcastsLocked();
265                    }
266                } catch (RemoteException e) {
267                    return false;
268                }
269            } else {
270                Intent statusChanged = new Intent();
271                statusChanged.putExtras(extras);
272                statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
273                try {
274                    synchronized (this) {
275                        // synchronize to ensure incrementPendingBroadcastsLocked()
276                        // is called before decrementPendingBroadcasts()
277                        mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
278                                mRequiredPermissions);
279                        // call this after broadcasting so we do not increment
280                        // if we throw an exeption.
281                        incrementPendingBroadcastsLocked();
282                    }
283                } catch (PendingIntent.CanceledException e) {
284                    return false;
285                }
286            }
287            return true;
288        }
289
290        public boolean callLocationChangedLocked(Location location) {
291            if (mListener != null) {
292                try {
293                    synchronized (this) {
294                        // synchronize to ensure incrementPendingBroadcastsLocked()
295                        // is called before decrementPendingBroadcasts()
296                        mListener.onLocationChanged(location);
297                        // call this after broadcasting so we do not increment
298                        // if we throw an exeption.
299                        incrementPendingBroadcastsLocked();
300                    }
301                } catch (RemoteException e) {
302                    return false;
303                }
304            } else {
305                Intent locationChanged = new Intent();
306                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
307                try {
308                    synchronized (this) {
309                        // synchronize to ensure incrementPendingBroadcastsLocked()
310                        // is called before decrementPendingBroadcasts()
311                        mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
312                                mRequiredPermissions);
313                        // call this after broadcasting so we do not increment
314                        // if we throw an exeption.
315                        incrementPendingBroadcastsLocked();
316                    }
317                } catch (PendingIntent.CanceledException e) {
318                    return false;
319                }
320            }
321            return true;
322        }
323
324        public boolean callProviderEnabledLocked(String provider, boolean enabled) {
325            if (mListener != null) {
326                try {
327                    synchronized (this) {
328                        // synchronize to ensure incrementPendingBroadcastsLocked()
329                        // is called before decrementPendingBroadcasts()
330                        if (enabled) {
331                            mListener.onProviderEnabled(provider);
332                        } else {
333                            mListener.onProviderDisabled(provider);
334                        }
335                        // call this after broadcasting so we do not increment
336                        // if we throw an exeption.
337                        incrementPendingBroadcastsLocked();
338                    }
339                } catch (RemoteException e) {
340                    return false;
341                }
342            } else {
343                Intent providerIntent = new Intent();
344                providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
345                try {
346                    synchronized (this) {
347                        // synchronize to ensure incrementPendingBroadcastsLocked()
348                        // is called before decrementPendingBroadcasts()
349                        mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
350                                mRequiredPermissions);
351                        // call this after broadcasting so we do not increment
352                        // if we throw an exeption.
353                        incrementPendingBroadcastsLocked();
354                    }
355                } catch (PendingIntent.CanceledException e) {
356                    return false;
357                }
358            }
359            return true;
360        }
361
362        @Override
363        public void binderDied() {
364            if (LOCAL_LOGV) {
365                Slog.v(TAG, "Location listener died");
366            }
367            synchronized (mLock) {
368                removeUpdatesLocked(this);
369            }
370            synchronized (this) {
371                if (mPendingBroadcasts > 0) {
372                    LocationManagerService.this.decrementPendingBroadcasts();
373                    mPendingBroadcasts = 0;
374                }
375            }
376        }
377
378        @Override
379        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
380                int resultCode, String resultData, Bundle resultExtras) {
381            synchronized (this) {
382                decrementPendingBroadcastsLocked();
383            }
384        }
385
386        // this must be called while synchronized by caller in a synchronized block
387        // containing the sending of the broadcaset
388        private void incrementPendingBroadcastsLocked() {
389            if (mPendingBroadcasts++ == 0) {
390                LocationManagerService.this.incrementPendingBroadcasts();
391            }
392        }
393
394        private void decrementPendingBroadcastsLocked() {
395            if (--mPendingBroadcasts == 0) {
396                LocationManagerService.this.decrementPendingBroadcasts();
397            }
398        }
399    }
400
401    @Override
402    public void locationCallbackFinished(ILocationListener listener) {
403        //Do not use getReceiver here as that will add the ILocationListener to
404        //the receiver list if it is not found.  If it is not found then the
405        //LocationListener was removed when it had a pending broadcast and should
406        //not be added back.
407        IBinder binder = listener.asBinder();
408        Receiver receiver = mReceivers.get(binder);
409        if (receiver != null) {
410            synchronized (receiver) {
411                // so wakelock calls will succeed
412                long identity = Binder.clearCallingIdentity();
413                receiver.decrementPendingBroadcastsLocked();
414                Binder.restoreCallingIdentity(identity);
415           }
416        }
417    }
418
419    private final class SettingsObserver implements Observer {
420        @Override
421        public void update(Observable o, Object arg) {
422            synchronized (mLock) {
423                updateProvidersLocked();
424            }
425        }
426    }
427
428    private void addProvider(LocationProviderInterface provider) {
429        mProviders.add(provider);
430        mProvidersByName.put(provider.getName(), provider);
431    }
432
433    private void removeProvider(LocationProviderInterface provider) {
434        mProviders.remove(provider);
435        mProvidersByName.remove(provider.getName());
436    }
437
438    private void loadProviders() {
439        synchronized (mLock) {
440            if (sProvidersLoaded) {
441                return;
442            }
443
444            // Load providers
445            loadProvidersLocked();
446            sProvidersLoaded = true;
447        }
448    }
449
450    private void loadProvidersLocked() {
451        try {
452            _loadProvidersLocked();
453        } catch (Exception e) {
454            Slog.e(TAG, "Exception loading providers:", e);
455        }
456    }
457
458    private void _loadProvidersLocked() {
459        // Attempt to load "real" providers first
460        if (GpsLocationProvider.isSupported()) {
461            // Create a gps location provider
462            GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
463            mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
464            mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
465            addProvider(gpsProvider);
466            mGpsLocationProvider = gpsProvider;
467        }
468
469        // create a passive location provider, which is always enabled
470        PassiveProvider passiveProvider = new PassiveProvider(this);
471        addProvider(passiveProvider);
472        mEnabledProviders.add(passiveProvider.getName());
473
474        // initialize external network location and geocoder services.
475        // The initial value of mNetworkLocationProviderPackageName and
476        // mGeocodeProviderPackageName is just used to determine what
477        // signatures future mNetworkLocationProviderPackageName and
478        // mGeocodeProviderPackageName packages must have. So alternate
479        // providers can be installed under a different package name
480        // so long as they have the same signature as the original
481        // provider packages.
482        if (mNetworkLocationProviderPackageName != null) {
483            String packageName = findBestPackage(LocationProviderProxy.SERVICE_ACTION,
484                    mNetworkLocationProviderPackageName);
485            if (packageName != null) {
486                mNetworkLocationProvider = new LocationProviderProxy(mContext,
487                        LocationManager.NETWORK_PROVIDER,
488                        packageName, mLocationHandler);
489                mNetworkLocationProviderPackageName = packageName;
490                addProvider(mNetworkLocationProvider);
491            }
492        }
493        if (mGeocodeProviderPackageName != null) {
494            String packageName = findBestPackage(GeocoderProxy.SERVICE_ACTION,
495                    mGeocodeProviderPackageName);
496            if (packageName != null) {
497                mGeocodeProvider = new GeocoderProxy(mContext, packageName);
498                mGeocodeProviderPackageName = packageName;
499            }
500        }
501
502        updateProvidersLocked();
503    }
504
505    /**
506     * Pick the best (network location provider or geocode provider) package.
507     * The best package:
508     * - implements serviceIntentName
509     * - has signatures that match that of sigPackageName
510     * - has the highest version value in a meta-data field in the service component
511     */
512    String findBestPackage(String serviceIntentName, String sigPackageName) {
513        Intent intent = new Intent(serviceIntentName);
514        List<ResolveInfo> infos = mPackageManager.queryIntentServices(intent,
515                PackageManager.GET_META_DATA);
516        if (infos == null) return null;
517
518        int bestVersion = Integer.MIN_VALUE;
519        String bestPackage = null;
520        for (ResolveInfo info : infos) {
521            String packageName = info.serviceInfo.packageName;
522            // check signature
523            if (mPackageManager.checkSignatures(packageName, sigPackageName) !=
524                    PackageManager.SIGNATURE_MATCH) {
525                Slog.w(TAG, packageName + " implements " + serviceIntentName +
526                       " but its signatures don't match those in " + sigPackageName +
527                       ", ignoring");
528                continue;
529            }
530            // read version
531            int version = 0;
532            if (info.serviceInfo.metaData != null) {
533                version = info.serviceInfo.metaData.getInt("version", 0);
534            }
535            if (LOCAL_LOGV) Slog.v(TAG, packageName + " implements " + serviceIntentName +
536                    " with version " + version);
537            if (version > bestVersion) {
538                bestVersion = version;
539                bestPackage = packageName;
540            }
541        }
542
543        return bestPackage;
544    }
545
546    /**
547     * @param context the context that the LocationManagerService runs in
548     */
549    public LocationManagerService(Context context) {
550        super();
551        mContext = context;
552        Resources resources = context.getResources();
553
554        mNetworkLocationProviderPackageName = resources.getString(
555                com.android.internal.R.string.config_networkLocationProviderPackageName);
556        mGeocodeProviderPackageName = resources.getString(
557                com.android.internal.R.string.config_geocodeProviderPackageName);
558
559        mPackageMonitor.register(context, null, true);
560
561        if (LOCAL_LOGV) {
562            Slog.v(TAG, "Constructed LocationManager Service");
563        }
564    }
565
566    void systemReady() {
567        // we defer starting up the service until the system is ready
568        Thread thread = new Thread(null, this, "LocationManagerService");
569        thread.start();
570    }
571
572    private void initialize() {
573        // Create a wake lock, needs to be done before calling loadProviders() below
574        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
575        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
576        mPackageManager = mContext.getPackageManager();
577
578        // Load providers
579        loadProviders();
580
581        // Register for Network (Wifi or Mobile) updates
582        IntentFilter intentFilter = new IntentFilter();
583        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
584        // Register for Package Manager updates
585        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
586        intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
587        intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
588        mContext.registerReceiver(mBroadcastReceiver, intentFilter);
589        IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
590        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
591
592        // listen for settings changes
593        ContentResolver resolver = mContext.getContentResolver();
594        Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
595                "(" + NameValueTable.NAME + "=?)",
596                new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
597                null);
598        mSettings = new ContentQueryMap(settingsCursor, NameValueTable.NAME, true, mLocationHandler);
599        SettingsObserver settingsObserver = new SettingsObserver();
600        mSettings.addObserver(settingsObserver);
601    }
602
603    @Override
604    public void run()
605    {
606        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
607        Looper.prepare();
608        mLocationHandler = new LocationWorkerHandler();
609        initialize();
610        mGeofenceManager = new GeofenceManager(mContext);
611        Looper.loop();
612    }
613
614    private boolean isAllowedBySettingsLocked(String provider) {
615        if (mEnabledProviders.contains(provider)) {
616            return true;
617        }
618        if (mDisabledProviders.contains(provider)) {
619            return false;
620        }
621        // Use system settings
622        ContentResolver resolver = mContext.getContentResolver();
623
624        return Settings.Secure.isLocationProviderEnabled(resolver, provider);
625    }
626
627    private String checkPermissionsSafe(String provider, String lastPermission) {
628        if (LocationManager.GPS_PROVIDER.equals(provider)
629                 || LocationManager.PASSIVE_PROVIDER.equals(provider)) {
630            if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
631                    != PackageManager.PERMISSION_GRANTED) {
632                throw new SecurityException("Provider " + provider
633                        + " requires ACCESS_FINE_LOCATION permission");
634            }
635            return ACCESS_FINE_LOCATION;
636        }
637
638        // Assume any other provider requires the coarse or fine permission.
639        if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
640                == PackageManager.PERMISSION_GRANTED) {
641            return ACCESS_FINE_LOCATION.equals(lastPermission)
642                    ? lastPermission : ACCESS_COARSE_LOCATION;
643        }
644        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
645                == PackageManager.PERMISSION_GRANTED) {
646            return ACCESS_FINE_LOCATION;
647        }
648
649        throw new SecurityException("Provider " + provider
650                + " requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
651    }
652
653    private boolean isAllowedProviderSafe(String provider) {
654        if ((LocationManager.GPS_PROVIDER.equals(provider)
655                || LocationManager.PASSIVE_PROVIDER.equals(provider))
656            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
657                != PackageManager.PERMISSION_GRANTED)) {
658            return false;
659        }
660        if (LocationManager.NETWORK_PROVIDER.equals(provider)
661            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
662                != PackageManager.PERMISSION_GRANTED)
663            && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
664                != PackageManager.PERMISSION_GRANTED)) {
665            return false;
666        }
667
668        return true;
669    }
670
671    @Override
672    public List<String> getAllProviders() {
673        try {
674            synchronized (mLock) {
675                return _getAllProvidersLocked();
676            }
677        } catch (SecurityException se) {
678            throw se;
679        } catch (Exception e) {
680            Slog.e(TAG, "getAllProviders got exception:", e);
681            return null;
682        }
683    }
684
685    private List<String> _getAllProvidersLocked() {
686        if (LOCAL_LOGV) {
687            Slog.v(TAG, "getAllProviders");
688        }
689        ArrayList<String> out = new ArrayList<String>(mProviders.size());
690        for (int i = mProviders.size() - 1; i >= 0; i--) {
691            LocationProviderInterface p = mProviders.get(i);
692            out.add(p.getName());
693        }
694        return out;
695    }
696
697    @Override
698    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
699        try {
700            synchronized (mLock) {
701                return _getProvidersLocked(criteria, enabledOnly);
702            }
703        } catch (SecurityException se) {
704            throw se;
705        } catch (Exception e) {
706            Slog.e(TAG, "getProviders got exception:", e);
707            return null;
708        }
709    }
710
711    private List<String> _getProvidersLocked(Criteria criteria, boolean enabledOnly) {
712        if (LOCAL_LOGV) {
713            Slog.v(TAG, "getProviders");
714        }
715        ArrayList<String> out = new ArrayList<String>(mProviders.size());
716        for (int i = mProviders.size() - 1; i >= 0; i--) {
717            LocationProviderInterface p = mProviders.get(i);
718            String name = p.getName();
719            if (isAllowedProviderSafe(name)) {
720                if (enabledOnly && !isAllowedBySettingsLocked(name)) {
721                    continue;
722                }
723                if (criteria != null && !p.meetsCriteria(criteria)) {
724                    continue;
725                }
726                out.add(name);
727            }
728        }
729        return out;
730    }
731
732    /**
733     * Returns the next looser power requirement, in the sequence:
734     *
735     * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT
736     */
737    private int nextPower(int power) {
738        switch (power) {
739        case Criteria.POWER_LOW:
740            return Criteria.POWER_MEDIUM;
741        case Criteria.POWER_MEDIUM:
742            return Criteria.POWER_HIGH;
743        case Criteria.POWER_HIGH:
744            return Criteria.NO_REQUIREMENT;
745        case Criteria.NO_REQUIREMENT:
746        default:
747            return Criteria.NO_REQUIREMENT;
748        }
749    }
750
751    /**
752     * Returns the next looser accuracy requirement, in the sequence:
753     *
754     * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT
755     */
756    private int nextAccuracy(int accuracy) {
757        if (accuracy == Criteria.ACCURACY_FINE) {
758            return Criteria.ACCURACY_COARSE;
759        } else {
760            return Criteria.NO_REQUIREMENT;
761        }
762    }
763
764    private class LpPowerComparator implements Comparator<LocationProviderInterface> {
765        @Override
766        public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
767            // Smaller is better
768            return (l1.getPowerRequirement() - l2.getPowerRequirement());
769         }
770
771         public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
772             return (l1.getPowerRequirement() == l2.getPowerRequirement());
773         }
774    }
775
776    private class LpAccuracyComparator implements Comparator<LocationProviderInterface> {
777        @Override
778        public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
779            // Smaller is better
780            return (l1.getAccuracy() - l2.getAccuracy());
781         }
782
783         public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
784             return (l1.getAccuracy() == l2.getAccuracy());
785         }
786    }
787
788    private class LpCapabilityComparator implements Comparator<LocationProviderInterface> {
789
790        private static final int ALTITUDE_SCORE = 4;
791        private static final int BEARING_SCORE = 4;
792        private static final int SPEED_SCORE = 4;
793
794        private int score(LocationProviderInterface p) {
795            return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) +
796                (p.supportsBearing() ? BEARING_SCORE : 0) +
797                (p.supportsSpeed() ? SPEED_SCORE : 0);
798        }
799
800        @Override
801        public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
802            return (score(l2) - score(l1)); // Bigger is better
803         }
804
805         public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
806             return (score(l1) == score(l2));
807         }
808    }
809
810    private LocationProviderInterface best(List<String> providerNames) {
811        ArrayList<LocationProviderInterface> providers;
812        synchronized (mLock) {
813            providers = new ArrayList<LocationProviderInterface>(providerNames.size());
814            for (String name : providerNames) {
815                providers.add(mProvidersByName.get(name));
816            }
817        }
818
819        if (providers.size() < 2) {
820            return providers.get(0);
821        }
822
823        // First, sort by power requirement
824        Collections.sort(providers, new LpPowerComparator());
825        int power = providers.get(0).getPowerRequirement();
826        if (power < providers.get(1).getPowerRequirement()) {
827            return providers.get(0);
828        }
829
830        int idx, size;
831
832        ArrayList<LocationProviderInterface> tmp = new ArrayList<LocationProviderInterface>();
833        idx = 0;
834        size = providers.size();
835        while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) {
836            tmp.add(providers.get(idx));
837            idx++;
838        }
839
840        // Next, sort by accuracy
841        Collections.sort(tmp, new LpAccuracyComparator());
842        int acc = tmp.get(0).getAccuracy();
843        if (acc < tmp.get(1).getAccuracy()) {
844            return tmp.get(0);
845        }
846
847        ArrayList<LocationProviderInterface> tmp2 = new ArrayList<LocationProviderInterface>();
848        idx = 0;
849        size = tmp.size();
850        while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) {
851            tmp2.add(tmp.get(idx));
852            idx++;
853        }
854
855        // Finally, sort by capability "score"
856        Collections.sort(tmp2, new LpCapabilityComparator());
857        return tmp2.get(0);
858    }
859
860    /**
861     * Returns the name of the provider that best meets the given criteria. Only providers
862     * that are permitted to be accessed by the calling activity will be
863     * returned.  If several providers meet the criteria, the one with the best
864     * accuracy is returned.  If no provider meets the criteria,
865     * the criteria are loosened in the following sequence:
866     *
867     * <ul>
868     * <li> power requirement
869     * <li> accuracy
870     * <li> bearing
871     * <li> speed
872     * <li> altitude
873     * </ul>
874     *
875     * <p> Note that the requirement on monetary cost is not removed
876     * in this process.
877     *
878     * @param criteria the criteria that need to be matched
879     * @param enabledOnly if true then only a provider that is currently enabled is returned
880     * @return name of the provider that best matches the requirements
881     */
882    @Override
883    public String getBestProvider(Criteria criteria, boolean enabledOnly) {
884        List<String> goodProviders = getProviders(criteria, enabledOnly);
885        if (!goodProviders.isEmpty()) {
886            return best(goodProviders).getName();
887        }
888
889        // Make a copy of the criteria that we can modify
890        criteria = new Criteria(criteria);
891
892        // Loosen power requirement
893        int power = criteria.getPowerRequirement();
894        while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) {
895            power = nextPower(power);
896            criteria.setPowerRequirement(power);
897            goodProviders = getProviders(criteria, enabledOnly);
898        }
899        if (!goodProviders.isEmpty()) {
900            return best(goodProviders).getName();
901        }
902
903        // Loosen accuracy requirement
904        int accuracy = criteria.getAccuracy();
905        while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) {
906            accuracy = nextAccuracy(accuracy);
907            criteria.setAccuracy(accuracy);
908            goodProviders = getProviders(criteria, enabledOnly);
909        }
910        if (!goodProviders.isEmpty()) {
911            return best(goodProviders).getName();
912        }
913
914        // Remove bearing requirement
915        criteria.setBearingRequired(false);
916        goodProviders = getProviders(criteria, enabledOnly);
917        if (!goodProviders.isEmpty()) {
918            return best(goodProviders).getName();
919        }
920
921        // Remove speed requirement
922        criteria.setSpeedRequired(false);
923        goodProviders = getProviders(criteria, enabledOnly);
924        if (!goodProviders.isEmpty()) {
925            return best(goodProviders).getName();
926        }
927
928        // Remove altitude requirement
929        criteria.setAltitudeRequired(false);
930        goodProviders = getProviders(criteria, enabledOnly);
931        if (!goodProviders.isEmpty()) {
932            return best(goodProviders).getName();
933        }
934
935        return null;
936    }
937
938    @Override
939    public boolean providerMeetsCriteria(String provider, Criteria criteria) {
940        LocationProviderInterface p = mProvidersByName.get(provider);
941        if (p == null) {
942            throw new IllegalArgumentException("provider=" + provider);
943        }
944        return p.meetsCriteria(criteria);
945    }
946
947    private void updateProvidersLocked() {
948        boolean changesMade = false;
949        for (int i = mProviders.size() - 1; i >= 0; i--) {
950            LocationProviderInterface p = mProviders.get(i);
951            boolean isEnabled = p.isEnabled();
952            String name = p.getName();
953            boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
954            if (isEnabled && !shouldBeEnabled) {
955                updateProviderListenersLocked(name, false);
956                changesMade = true;
957            } else if (!isEnabled && shouldBeEnabled) {
958                updateProviderListenersLocked(name, true);
959                changesMade = true;
960            }
961        }
962        if (changesMade) {
963            mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
964        }
965    }
966
967    private void updateProviderListenersLocked(String provider, boolean enabled) {
968        int listeners = 0;
969
970        LocationProviderInterface p = mProvidersByName.get(provider);
971        if (p == null) {
972            return;
973        }
974
975        ArrayList<Receiver> deadReceivers = null;
976
977        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
978        if (records != null) {
979            final int N = records.size();
980            for (int i=0; i<N; i++) {
981                UpdateRecord record = records.get(i);
982                // Sends a notification message to the receiver
983                if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
984                    if (deadReceivers == null) {
985                        deadReceivers = new ArrayList<Receiver>();
986                    }
987                    deadReceivers.add(record.mReceiver);
988                }
989                listeners++;
990            }
991        }
992
993        if (deadReceivers != null) {
994            for (int i=deadReceivers.size()-1; i>=0; i--) {
995                removeUpdatesLocked(deadReceivers.get(i));
996            }
997        }
998
999        if (enabled) {
1000            p.enable();
1001            if (listeners > 0) {
1002                p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);
1003                p.enableLocationTracking(true);
1004            }
1005        } else {
1006            p.enableLocationTracking(false);
1007            p.disable();
1008        }
1009    }
1010
1011    private long getMinTimeLocked(String provider) {
1012        long minTime = Long.MAX_VALUE;
1013        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1014        mTmpWorkSource.clear();
1015        if (records != null) {
1016            for (int i=records.size()-1; i>=0; i--) {
1017                UpdateRecord ur = records.get(i);
1018                long curTime = ur.mMinTime;
1019                if (curTime < minTime) {
1020                    minTime = curTime;
1021                }
1022            }
1023            long inclTime = (minTime*3)/2;
1024            for (int i=records.size()-1; i>=0; i--) {
1025                UpdateRecord ur = records.get(i);
1026                if (ur.mMinTime <= inclTime) {
1027                    mTmpWorkSource.add(ur.mUid);
1028                }
1029            }
1030        }
1031        return minTime;
1032    }
1033
1034    private class UpdateRecord {
1035        final String mProvider;
1036        final Receiver mReceiver;
1037        final long mMinTime;
1038        final float mMinDistance;
1039        final boolean mSingleShot;
1040        final int mUid;
1041        Location mLastFixBroadcast;
1042        long mLastStatusBroadcast;
1043
1044        /**
1045         * Note: must be constructed with lock held.
1046         */
1047        UpdateRecord(String provider, long minTime, float minDistance, boolean singleShot,
1048            Receiver receiver, int uid) {
1049            mProvider = provider;
1050            mReceiver = receiver;
1051            mMinTime = minTime;
1052            mMinDistance = minDistance;
1053            mSingleShot = singleShot;
1054            mUid = uid;
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() {
1071            ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
1072            if (records != null) {
1073                records.remove(this);
1074            }
1075        }
1076
1077        @Override
1078        public String toString() {
1079            return "UpdateRecord{"
1080                    + Integer.toHexString(System.identityHashCode(this))
1081                    + " mProvider: " + mProvider + " mUid: " + mUid + "}";
1082        }
1083
1084        void dump(PrintWriter pw, String prefix) {
1085            pw.println(prefix + this);
1086            pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
1087            pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
1088            pw.println(prefix + "mSingleShot=" + mSingleShot);
1089            pw.println(prefix + "mUid=" + mUid);
1090            pw.println(prefix + "mLastFixBroadcast:");
1091            if (mLastFixBroadcast != null) {
1092                mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + "  ");
1093            }
1094            pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
1095        }
1096    }
1097
1098    private Receiver getReceiver(ILocationListener listener) {
1099        IBinder binder = listener.asBinder();
1100        Receiver receiver = mReceivers.get(binder);
1101        if (receiver == null) {
1102            receiver = new Receiver(listener);
1103            mReceivers.put(binder, receiver);
1104
1105            try {
1106                if (receiver.isListener()) {
1107                    receiver.getListener().asBinder().linkToDeath(receiver, 0);
1108                }
1109            } catch (RemoteException e) {
1110                Slog.e(TAG, "linkToDeath failed:", e);
1111                return null;
1112            }
1113        }
1114        return receiver;
1115    }
1116
1117    private Receiver getReceiver(PendingIntent intent) {
1118        Receiver receiver = mReceivers.get(intent);
1119        if (receiver == null) {
1120            receiver = new Receiver(intent);
1121            mReceivers.put(intent, receiver);
1122        }
1123        return receiver;
1124    }
1125
1126    private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) {
1127        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1128        if (records != null) {
1129            for (int i = records.size() - 1; i >= 0; i--) {
1130                UpdateRecord record = records.get(i);
1131                if (record.mUid == uid && record.mReceiver != excludedReceiver) {
1132                    return true;
1133                }
1134           }
1135        }
1136        return false;
1137    }
1138
1139    @Override
1140    public void requestLocationUpdates(String provider, Criteria criteria,
1141        long minTime, float minDistance, boolean singleShot, ILocationListener listener) {
1142        if (criteria != null) {
1143            // FIXME - should we consider using multiple providers simultaneously
1144            // rather than only the best one?
1145            // Should we do anything different for single shot fixes?
1146            provider = getBestProvider(criteria, true);
1147            if (provider == null) {
1148                throw new IllegalArgumentException("no providers found for criteria");
1149            }
1150        }
1151        try {
1152            synchronized (mLock) {
1153                requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
1154                        getReceiver(listener));
1155            }
1156        } catch (SecurityException se) {
1157            throw se;
1158        } catch (IllegalArgumentException iae) {
1159            throw iae;
1160        } catch (Exception e) {
1161            Slog.e(TAG, "requestUpdates got exception:", e);
1162        }
1163    }
1164
1165    void validatePackageName(int uid, String packageName) {
1166        if (packageName == null) {
1167            throw new SecurityException("packageName cannot be null");
1168        }
1169        String[] packages = mPackageManager.getPackagesForUid(uid);
1170        if (packages == null) {
1171            throw new SecurityException("invalid UID " + uid);
1172        }
1173        for (String pkg : packages) {
1174            if (packageName.equals(pkg)) return;
1175        }
1176        throw new SecurityException("invalid package name");
1177    }
1178
1179    void validatePendingIntent(PendingIntent intent) {
1180        if (intent.isTargetedToPackage()) {
1181            return;
1182        }
1183        Slog.i(TAG, "Given Intent does not require a specific package: "
1184                + intent);
1185        // XXX we should really throw a security exception, if the caller's
1186        // targetSdkVersion is high enough.
1187        //throw new SecurityException("Given Intent does not require a specific package: "
1188        //        + intent);
1189    }
1190
1191    @Override
1192    public void requestLocationUpdatesPI(String provider, Criteria criteria,
1193            long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
1194        validatePendingIntent(intent);
1195        if (criteria != null) {
1196            // FIXME - should we consider using multiple providers simultaneously
1197            // rather than only the best one?
1198            // Should we do anything different for single shot fixes?
1199            provider = getBestProvider(criteria, true);
1200            if (provider == null) {
1201                throw new IllegalArgumentException("no providers found for criteria");
1202            }
1203        }
1204        try {
1205            synchronized (mLock) {
1206                requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
1207                        getReceiver(intent));
1208            }
1209        } catch (SecurityException se) {
1210            throw se;
1211        } catch (IllegalArgumentException iae) {
1212            throw iae;
1213        } catch (Exception e) {
1214            Slog.e(TAG, "requestUpdates got exception:", e);
1215        }
1216    }
1217
1218    private void requestLocationUpdatesLocked(String provider, long minTime, float minDistance,
1219            boolean singleShot, Receiver receiver) {
1220
1221        LocationProviderInterface p = mProvidersByName.get(provider);
1222        if (p == null) {
1223            throw new IllegalArgumentException("requested provider " + provider +
1224                    " doesn't exisit");
1225        }
1226        receiver.mRequiredPermissions = checkPermissionsSafe(provider,
1227                receiver.mRequiredPermissions);
1228
1229        // so wakelock calls will succeed
1230        final int callingPid = Binder.getCallingPid();
1231        final int callingUid = Binder.getCallingUid();
1232        boolean newUid = !providerHasListener(provider, callingUid, null);
1233        long identity = Binder.clearCallingIdentity();
1234        try {
1235            UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, singleShot,
1236                    receiver, callingUid);
1237            UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
1238            if (oldRecord != null) {
1239                oldRecord.disposeLocked();
1240            }
1241
1242            if (newUid) {
1243                p.addListener(callingUid);
1244            }
1245
1246            boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
1247            if (isProviderEnabled) {
1248                long minTimeForProvider = getMinTimeLocked(provider);
1249                Slog.i(TAG, "request " + provider + " (pid " + callingPid + ") " + minTime +
1250                        " " + minTimeForProvider + (singleShot ? " (singleshot)" : ""));
1251                p.setMinTime(minTimeForProvider, mTmpWorkSource);
1252                // try requesting single shot if singleShot is true, and fall back to
1253                // regular location tracking if requestSingleShotFix() is not supported
1254                if (!singleShot || !p.requestSingleShotFix()) {
1255                    p.enableLocationTracking(true);
1256                }
1257            } else {
1258                // Notify the listener that updates are currently disabled
1259                receiver.callProviderEnabledLocked(provider, false);
1260            }
1261            if (LOCAL_LOGV) {
1262                Slog.v(TAG, "_requestLocationUpdates: provider = " + provider + " listener = " + receiver);
1263            }
1264        } finally {
1265            Binder.restoreCallingIdentity(identity);
1266        }
1267    }
1268
1269    @Override
1270    public void removeUpdates(ILocationListener listener) {
1271        try {
1272            synchronized (mLock) {
1273                removeUpdatesLocked(getReceiver(listener));
1274            }
1275        } catch (SecurityException se) {
1276            throw se;
1277        } catch (IllegalArgumentException iae) {
1278            throw iae;
1279        } catch (Exception e) {
1280            Slog.e(TAG, "removeUpdates got exception:", e);
1281        }
1282    }
1283
1284    @Override
1285    public void removeUpdatesPI(PendingIntent intent) {
1286        try {
1287            synchronized (mLock) {
1288                removeUpdatesLocked(getReceiver(intent));
1289            }
1290        } catch (SecurityException se) {
1291            throw se;
1292        } catch (IllegalArgumentException iae) {
1293            throw iae;
1294        } catch (Exception e) {
1295            Slog.e(TAG, "removeUpdates got exception:", e);
1296        }
1297    }
1298
1299    private void removeUpdatesLocked(Receiver receiver) {
1300        if (LOCAL_LOGV) {
1301            Slog.v(TAG, "_removeUpdates: listener = " + receiver);
1302        }
1303
1304        // so wakelock calls will succeed
1305        final int callingPid = Binder.getCallingPid();
1306        final int callingUid = Binder.getCallingUid();
1307        long identity = Binder.clearCallingIdentity();
1308        try {
1309            if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1310                receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1311                synchronized(receiver) {
1312                    if(receiver.mPendingBroadcasts > 0) {
1313                        decrementPendingBroadcasts();
1314                        receiver.mPendingBroadcasts = 0;
1315                    }
1316                }
1317            }
1318
1319            // Record which providers were associated with this listener
1320            HashSet<String> providers = new HashSet<String>();
1321            HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords;
1322            if (oldRecords != null) {
1323                // Call dispose() on the obsolete update records.
1324                for (UpdateRecord record : oldRecords.values()) {
1325                    if (!providerHasListener(record.mProvider, callingUid, receiver)) {
1326                        LocationProviderInterface p = mProvidersByName.get(record.mProvider);
1327                        if (p != null) {
1328                            p.removeListener(callingUid);
1329                        }
1330                    }
1331                    record.disposeLocked();
1332                }
1333                // Accumulate providers
1334                providers.addAll(oldRecords.keySet());
1335            }
1336
1337            // See if the providers associated with this listener have any
1338            // other listeners; if one does, inform it of the new smallest minTime
1339            // value; if one does not, disable location tracking for it
1340            for (String provider : providers) {
1341                // If provider is already disabled, don't need to do anything
1342                if (!isAllowedBySettingsLocked(provider)) {
1343                    continue;
1344                }
1345
1346                boolean hasOtherListener = false;
1347                ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
1348                if (recordsForProvider != null && recordsForProvider.size() > 0) {
1349                    hasOtherListener = true;
1350                }
1351
1352                LocationProviderInterface p = mProvidersByName.get(provider);
1353                if (p != null) {
1354                    if (hasOtherListener) {
1355                        long minTime = getMinTimeLocked(provider);
1356                        Slog.i(TAG, "remove " + provider + " (pid " + callingPid +
1357                                "), next minTime = " + minTime);
1358                        p.setMinTime(minTime, mTmpWorkSource);
1359                    } else {
1360                        Slog.i(TAG, "remove " + provider + " (pid " + callingPid +
1361                                "), disabled");
1362                        p.enableLocationTracking(false);
1363                    }
1364                }
1365            }
1366        } finally {
1367            Binder.restoreCallingIdentity(identity);
1368        }
1369    }
1370
1371    @Override
1372    public boolean addGpsStatusListener(IGpsStatusListener listener) {
1373        if (mGpsStatusProvider == null) {
1374            return false;
1375        }
1376        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
1377                PackageManager.PERMISSION_GRANTED) {
1378            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1379        }
1380
1381        try {
1382            mGpsStatusProvider.addGpsStatusListener(listener);
1383        } catch (RemoteException e) {
1384            Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
1385            return false;
1386        }
1387        return true;
1388    }
1389
1390    @Override
1391    public void removeGpsStatusListener(IGpsStatusListener listener) {
1392        synchronized (mLock) {
1393            try {
1394                mGpsStatusProvider.removeGpsStatusListener(listener);
1395            } catch (Exception e) {
1396                Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1397            }
1398        }
1399    }
1400
1401    @Override
1402    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1403        if (provider == null) {
1404            // throw NullPointerException to remain compatible with previous implementation
1405            throw new NullPointerException();
1406        }
1407
1408        // first check for permission to the provider
1409        checkPermissionsSafe(provider, null);
1410        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1411        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1412                != PackageManager.PERMISSION_GRANTED)) {
1413            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1414        }
1415
1416        synchronized (mLock) {
1417            LocationProviderInterface p = mProvidersByName.get(provider);
1418            if (p == null) {
1419                return false;
1420            }
1421
1422            return p.sendExtraCommand(command, extras);
1423        }
1424    }
1425
1426    @Override
1427    public boolean sendNiResponse(int notifId, int userResponse)
1428    {
1429        if (Binder.getCallingUid() != Process.myUid()) {
1430            throw new SecurityException(
1431                    "calling sendNiResponse from outside of the system is not allowed");
1432        }
1433        try {
1434            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1435        }
1436        catch (RemoteException e)
1437        {
1438            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1439            return false;
1440        }
1441    }
1442
1443    @Override
1444    public void addProximityAlert(double latitude, double longitude,
1445            float radius, long expiration, PendingIntent intent, String packageName) {
1446        validatePendingIntent(intent);
1447        validatePackageName(Binder.getCallingUid(), packageName);
1448
1449        // Require ability to access all providers for now
1450        if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1451            !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1452            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1453        }
1454
1455        if (LOCAL_LOGV) Slog.v(TAG, "addProximityAlert: lat=" + latitude + ", long=" + longitude +
1456                ", radius=" + radius + ", exp=" + expiration + ", intent = " + intent);
1457
1458        mGeofenceManager.addFence(latitude, longitude, radius, expiration, intent,
1459                Binder.getCallingUid(), packageName);
1460    }
1461
1462    @Override
1463    public void removeProximityAlert(PendingIntent intent) {
1464        if (intent == null) throw new NullPointerException("pending intent is null");
1465
1466        if (LOCAL_LOGV) Slog.v(TAG, "removeProximityAlert: intent = " + intent);
1467
1468        mGeofenceManager.removeFence(intent);
1469    }
1470
1471    /**
1472     * @return null if the provider does not exist
1473     * @throws SecurityException if the provider is not allowed to be
1474     * accessed by the caller
1475     */
1476    @Override
1477    public Bundle getProviderInfo(String provider) {
1478        try {
1479            synchronized (mLock) {
1480                return _getProviderInfoLocked(provider);
1481            }
1482        } catch (SecurityException se) {
1483            throw se;
1484        } catch (IllegalArgumentException iae) {
1485            throw iae;
1486        } catch (Exception e) {
1487            Slog.e(TAG, "_getProviderInfo got exception:", e);
1488            return null;
1489        }
1490    }
1491
1492    private Bundle _getProviderInfoLocked(String provider) {
1493        LocationProviderInterface p = mProvidersByName.get(provider);
1494        if (p == null) {
1495            return null;
1496        }
1497
1498        checkPermissionsSafe(provider, null);
1499
1500        Bundle b = new Bundle();
1501        b.putBoolean("network", p.requiresNetwork());
1502        b.putBoolean("satellite", p.requiresSatellite());
1503        b.putBoolean("cell", p.requiresCell());
1504        b.putBoolean("cost", p.hasMonetaryCost());
1505        b.putBoolean("altitude", p.supportsAltitude());
1506        b.putBoolean("speed", p.supportsSpeed());
1507        b.putBoolean("bearing", p.supportsBearing());
1508        b.putInt("power", p.getPowerRequirement());
1509        b.putInt("accuracy", p.getAccuracy());
1510
1511        return b;
1512    }
1513
1514    @Override
1515    public boolean isProviderEnabled(String provider) {
1516        try {
1517            synchronized (mLock) {
1518                return _isProviderEnabledLocked(provider);
1519            }
1520        } catch (SecurityException se) {
1521            throw se;
1522        } catch (Exception e) {
1523            Slog.e(TAG, "isProviderEnabled got exception:", e);
1524            return false;
1525        }
1526    }
1527
1528    @Override
1529    public void reportLocation(Location location, boolean passive) {
1530        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1531                != PackageManager.PERMISSION_GRANTED) {
1532            throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
1533        }
1534
1535        if (!location.isComplete()) {
1536            Log.w(TAG, "Dropping incomplete location: " + location);
1537            return;
1538        }
1539
1540        mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1541        Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
1542        m.arg1 = (passive ? 1 : 0);
1543        mLocationHandler.sendMessageAtFrontOfQueue(m);
1544    }
1545
1546    private boolean _isProviderEnabledLocked(String provider) {
1547        checkPermissionsSafe(provider, null);
1548
1549        LocationProviderInterface p = mProvidersByName.get(provider);
1550        if (p == null) {
1551            return false;
1552        }
1553        return isAllowedBySettingsLocked(provider);
1554    }
1555
1556    @Override
1557    public Location getLastKnownLocation(String provider) {
1558        if (LOCAL_LOGV) {
1559            Slog.v(TAG, "getLastKnownLocation: " + provider);
1560        }
1561        try {
1562            synchronized (mLock) {
1563                return _getLastKnownLocationLocked(provider);
1564            }
1565        } catch (SecurityException se) {
1566            throw se;
1567        } catch (Exception e) {
1568            Slog.e(TAG, "getLastKnownLocation got exception:", e);
1569            return null;
1570        }
1571    }
1572
1573    private Location _getLastKnownLocationLocked(String provider) {
1574        checkPermissionsSafe(provider, null);
1575
1576        LocationProviderInterface p = mProvidersByName.get(provider);
1577        if (p == null) {
1578            return null;
1579        }
1580
1581        if (!isAllowedBySettingsLocked(provider)) {
1582            return null;
1583        }
1584
1585        return mLastKnownLocation.get(provider);
1586    }
1587
1588    private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1589        // Always broadcast the first update
1590        if (lastLoc == null) {
1591            return true;
1592        }
1593
1594        // Check whether sufficient time has passed
1595        long minTime = record.mMinTime;
1596        long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
1597        if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER) {
1598            return false;
1599        }
1600
1601        // Check whether sufficient distance has been traveled
1602        double minDistance = record.mMinDistance;
1603        if (minDistance > 0.0) {
1604            if (loc.distanceTo(lastLoc) <= minDistance) {
1605                return false;
1606            }
1607        }
1608
1609        return true;
1610    }
1611
1612    private void handleLocationChangedLocked(Location location, boolean passive) {
1613        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
1614        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1615        if (records == null || records.size() == 0) {
1616            return;
1617        }
1618
1619        LocationProviderInterface p = mProvidersByName.get(provider);
1620        if (p == null) {
1621            return;
1622        }
1623
1624        // Update last known location for provider
1625        Location lastLocation = mLastKnownLocation.get(provider);
1626        if (lastLocation == null) {
1627            mLastKnownLocation.put(provider, new Location(location));
1628        } else {
1629            lastLocation.set(location);
1630        }
1631
1632        // Fetch latest status update time
1633        long newStatusUpdateTime = p.getStatusUpdateTime();
1634
1635       // Get latest status
1636        Bundle extras = new Bundle();
1637        int status = p.getStatus(extras);
1638
1639        ArrayList<Receiver> deadReceivers = null;
1640
1641        // Broadcast location or status to all listeners
1642        final int N = records.size();
1643        for (int i=0; i<N; i++) {
1644            UpdateRecord r = records.get(i);
1645            Receiver receiver = r.mReceiver;
1646            boolean receiverDead = false;
1647
1648            Location lastLoc = r.mLastFixBroadcast;
1649            if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1650                if (lastLoc == null) {
1651                    lastLoc = new Location(location);
1652                    r.mLastFixBroadcast = lastLoc;
1653                } else {
1654                    lastLoc.set(location);
1655                }
1656                if (!receiver.callLocationChangedLocked(location)) {
1657                    Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1658                    receiverDead = true;
1659                }
1660            }
1661
1662            long prevStatusUpdateTime = r.mLastStatusBroadcast;
1663            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1664                (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1665
1666                r.mLastStatusBroadcast = newStatusUpdateTime;
1667                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1668                    receiverDead = true;
1669                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1670                }
1671            }
1672
1673            // remove receiver if it is dead or we just processed a single shot request
1674            if (receiverDead || r.mSingleShot) {
1675                if (deadReceivers == null) {
1676                    deadReceivers = new ArrayList<Receiver>();
1677                }
1678                if (!deadReceivers.contains(receiver)) {
1679                    deadReceivers.add(receiver);
1680                }
1681            }
1682        }
1683
1684        if (deadReceivers != null) {
1685            for (int i=deadReceivers.size()-1; i>=0; i--) {
1686                removeUpdatesLocked(deadReceivers.get(i));
1687            }
1688        }
1689    }
1690
1691    private class LocationWorkerHandler extends Handler {
1692
1693        @Override
1694        public void handleMessage(Message msg) {
1695            try {
1696                if (msg.what == MESSAGE_LOCATION_CHANGED) {
1697                    // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
1698
1699                    synchronized (mLock) {
1700                        Location location = (Location) msg.obj;
1701                        String provider = location.getProvider();
1702                        boolean passive = (msg.arg1 == 1);
1703
1704                        if (!passive) {
1705                            // notify other providers of the new location
1706                            for (int i = mProviders.size() - 1; i >= 0; i--) {
1707                                LocationProviderInterface p = mProviders.get(i);
1708                                if (!provider.equals(p.getName())) {
1709                                    p.updateLocation(location);
1710                                }
1711                            }
1712                        }
1713
1714                        if (isAllowedBySettingsLocked(provider)) {
1715                            handleLocationChangedLocked(location, passive);
1716                        }
1717                    }
1718                } else if (msg.what == MESSAGE_PACKAGE_UPDATED) {
1719                    String packageName = (String) msg.obj;
1720
1721                    // reconnect to external providers if there is a better package
1722                    if (mNetworkLocationProviderPackageName != null &&
1723                            mPackageManager.resolveService(
1724                            new Intent(LocationProviderProxy.SERVICE_ACTION)
1725                            .setPackage(packageName), 0) != null) {
1726                        // package implements service, perform full check
1727                        String bestPackage = findBestPackage(
1728                                LocationProviderProxy.SERVICE_ACTION,
1729                                mNetworkLocationProviderPackageName);
1730                        if (packageName.equals(bestPackage)) {
1731                            mNetworkLocationProvider.reconnect(bestPackage);
1732                            mNetworkLocationProviderPackageName = packageName;
1733                        }
1734                    }
1735                    if (mGeocodeProviderPackageName != null &&
1736                            mPackageManager.resolveService(
1737                            new Intent(GeocoderProxy.SERVICE_ACTION)
1738                            .setPackage(packageName), 0) != null) {
1739                        // package implements service, perform full check
1740                        String bestPackage = findBestPackage(
1741                                GeocoderProxy.SERVICE_ACTION,
1742                                mGeocodeProviderPackageName);
1743                        if (packageName.equals(bestPackage)) {
1744                            mGeocodeProvider.reconnect(bestPackage);
1745                            mGeocodeProviderPackageName = packageName;
1746                        }
1747                    }
1748                }
1749            } catch (Exception e) {
1750                // Log, don't crash!
1751                Slog.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1752            }
1753        }
1754    }
1755
1756    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1757        @Override
1758        public void onReceive(Context context, Intent intent) {
1759            String action = intent.getAction();
1760            boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART);
1761            if (queryRestart
1762                    || action.equals(Intent.ACTION_PACKAGE_REMOVED)
1763                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
1764                    || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
1765                synchronized (mLock) {
1766                    int uidList[] = null;
1767                    if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
1768                        uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1769                    } else {
1770                        uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)};
1771                    }
1772                    if (uidList == null || uidList.length == 0) {
1773                        return;
1774                    }
1775                    for (int uid : uidList) {
1776                        if (uid >= 0) {
1777                            ArrayList<Receiver> removedRecs = null;
1778                            for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1779                                for (int j=i.size()-1; j>=0; j--) {
1780                                    UpdateRecord ur = i.get(j);
1781                                    if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
1782                                        if (queryRestart) {
1783                                            setResultCode(Activity.RESULT_OK);
1784                                            return;
1785                                        }
1786                                        if (removedRecs == null) {
1787                                            removedRecs = new ArrayList<Receiver>();
1788                                        }
1789                                        if (!removedRecs.contains(ur.mReceiver)) {
1790                                            removedRecs.add(ur.mReceiver);
1791                                        }
1792                                    }
1793                                }
1794                            }
1795                        }
1796                    }
1797                }
1798            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1799                boolean noConnectivity =
1800                    intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1801                if (!noConnectivity) {
1802                    mNetworkState = LocationProvider.AVAILABLE;
1803                } else {
1804                    mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
1805                }
1806
1807                final NetworkInfo info = intent.getParcelableExtra(
1808                        ConnectivityManager.EXTRA_NETWORK_INFO);
1809
1810                // Notify location providers of current network state
1811                synchronized (mLock) {
1812                    for (int i = mProviders.size() - 1; i >= 0; i--) {
1813                        LocationProviderInterface provider = mProviders.get(i);
1814                        if (provider.requiresNetwork()) {
1815                            provider.updateNetworkState(mNetworkState, info);
1816                        }
1817                    }
1818                }
1819            }
1820        }
1821    };
1822
1823    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1824        @Override
1825        public void onPackageUpdateFinished(String packageName, int uid) {
1826            // Called by main thread; divert work to LocationWorker.
1827            Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
1828        }
1829        @Override
1830        public void onPackageAdded(String packageName, int uid) {
1831            // Called by main thread; divert work to LocationWorker.
1832            Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
1833        }
1834        @Override
1835        public void onPackageDisappeared(String packageName, int uid) {
1836            mGeofenceManager.removeFence(packageName);
1837        }
1838    };
1839
1840    // Wake locks
1841
1842    private void incrementPendingBroadcasts() {
1843        synchronized (mWakeLock) {
1844            if (mPendingBroadcasts++ == 0) {
1845                try {
1846                    mWakeLock.acquire();
1847                    log("Acquired wakelock");
1848                } catch (Exception e) {
1849                    // This is to catch a runtime exception thrown when we try to release an
1850                    // already released lock.
1851                    Slog.e(TAG, "exception in acquireWakeLock()", e);
1852                }
1853            }
1854        }
1855    }
1856
1857    private void decrementPendingBroadcasts() {
1858        synchronized (mWakeLock) {
1859            if (--mPendingBroadcasts == 0) {
1860                try {
1861                    // Release wake lock
1862                    if (mWakeLock.isHeld()) {
1863                        mWakeLock.release();
1864                        log("Released wakelock");
1865                    } else {
1866                        log("Can't release wakelock again!");
1867                    }
1868                } catch (Exception e) {
1869                    // This is to catch a runtime exception thrown when we try to release an
1870                    // already released lock.
1871                    Slog.e(TAG, "exception in releaseWakeLock()", e);
1872                }
1873            }
1874        }
1875    }
1876
1877    // Geocoder
1878
1879    @Override
1880    public boolean geocoderIsPresent() {
1881        return mGeocodeProvider != null;
1882    }
1883
1884    @Override
1885    public String getFromLocation(double latitude, double longitude, int maxResults,
1886            GeocoderParams params, List<Address> addrs) {
1887        if (mGeocodeProvider != null) {
1888            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1889                    params, addrs);
1890        }
1891        return null;
1892    }
1893
1894
1895    @Override
1896    public String getFromLocationName(String locationName,
1897            double lowerLeftLatitude, double lowerLeftLongitude,
1898            double upperRightLatitude, double upperRightLongitude, int maxResults,
1899            GeocoderParams params, List<Address> addrs) {
1900
1901        if (mGeocodeProvider != null) {
1902            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1903                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1904                    maxResults, params, addrs);
1905        }
1906        return null;
1907    }
1908
1909    // Mock Providers
1910
1911    private void checkMockPermissionsSafe() {
1912        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1913                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1914        if (!allowMocks) {
1915            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1916        }
1917
1918        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1919            PackageManager.PERMISSION_GRANTED) {
1920            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1921        }
1922    }
1923
1924    @Override
1925    public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
1926        boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1927        boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1928        checkMockPermissionsSafe();
1929
1930        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1931            throw new IllegalArgumentException("Cannot mock the passive location provider");
1932        }
1933
1934        long identity = Binder.clearCallingIdentity();
1935        synchronized (mLock) {
1936            MockProvider provider = new MockProvider(name, this,
1937                requiresNetwork, requiresSatellite,
1938                requiresCell, hasMonetaryCost, supportsAltitude,
1939                supportsSpeed, supportsBearing, powerRequirement, accuracy);
1940            // remove the real provider if we are replacing GPS or network provider
1941            if (LocationManager.GPS_PROVIDER.equals(name)
1942                    || LocationManager.NETWORK_PROVIDER.equals(name)) {
1943                LocationProviderInterface p = mProvidersByName.get(name);
1944                if (p != null) {
1945                    p.enableLocationTracking(false);
1946                    removeProvider(p);
1947                }
1948            }
1949            if (mProvidersByName.get(name) != null) {
1950                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1951            }
1952            addProvider(provider);
1953            mMockProviders.put(name, provider);
1954            mLastKnownLocation.put(name, null);
1955            updateProvidersLocked();
1956        }
1957        Binder.restoreCallingIdentity(identity);
1958    }
1959
1960    @Override
1961    public void removeTestProvider(String provider) {
1962        checkMockPermissionsSafe();
1963        synchronized (mLock) {
1964            MockProvider mockProvider = mMockProviders.get(provider);
1965            if (mockProvider == null) {
1966                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1967            }
1968            long identity = Binder.clearCallingIdentity();
1969            removeProvider(mProvidersByName.get(provider));
1970            mMockProviders.remove(mockProvider);
1971            // reinstall real provider if we were mocking GPS or network provider
1972            if (LocationManager.GPS_PROVIDER.equals(provider) &&
1973                    mGpsLocationProvider != null) {
1974                addProvider(mGpsLocationProvider);
1975            } else if (LocationManager.NETWORK_PROVIDER.equals(provider) &&
1976                    mNetworkLocationProvider != null) {
1977                addProvider(mNetworkLocationProvider);
1978            }
1979            mLastKnownLocation.put(provider, null);
1980            updateProvidersLocked();
1981            Binder.restoreCallingIdentity(identity);
1982        }
1983    }
1984
1985    @Override
1986    public void setTestProviderLocation(String provider, Location loc) {
1987        checkMockPermissionsSafe();
1988        synchronized (mLock) {
1989            MockProvider mockProvider = mMockProviders.get(provider);
1990            if (mockProvider == null) {
1991                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1992            }
1993            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1994            long identity = Binder.clearCallingIdentity();
1995            mockProvider.setLocation(loc);
1996            Binder.restoreCallingIdentity(identity);
1997        }
1998    }
1999
2000    @Override
2001    public void clearTestProviderLocation(String provider) {
2002        checkMockPermissionsSafe();
2003        synchronized (mLock) {
2004            MockProvider mockProvider = mMockProviders.get(provider);
2005            if (mockProvider == null) {
2006                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2007            }
2008            mockProvider.clearLocation();
2009        }
2010    }
2011
2012    @Override
2013    public void setTestProviderEnabled(String provider, boolean enabled) {
2014        checkMockPermissionsSafe();
2015        synchronized (mLock) {
2016            MockProvider mockProvider = mMockProviders.get(provider);
2017            if (mockProvider == null) {
2018                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2019            }
2020            long identity = Binder.clearCallingIdentity();
2021            if (enabled) {
2022                mockProvider.enable();
2023                mEnabledProviders.add(provider);
2024                mDisabledProviders.remove(provider);
2025            } else {
2026                mockProvider.disable();
2027                mEnabledProviders.remove(provider);
2028                mDisabledProviders.add(provider);
2029            }
2030            updateProvidersLocked();
2031            Binder.restoreCallingIdentity(identity);
2032        }
2033    }
2034
2035    @Override
2036    public void clearTestProviderEnabled(String provider) {
2037        checkMockPermissionsSafe();
2038        synchronized (mLock) {
2039            MockProvider mockProvider = mMockProviders.get(provider);
2040            if (mockProvider == null) {
2041                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2042            }
2043            long identity = Binder.clearCallingIdentity();
2044            mEnabledProviders.remove(provider);
2045            mDisabledProviders.remove(provider);
2046            updateProvidersLocked();
2047            Binder.restoreCallingIdentity(identity);
2048        }
2049    }
2050
2051    @Override
2052    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2053        checkMockPermissionsSafe();
2054        synchronized (mLock) {
2055            MockProvider mockProvider = mMockProviders.get(provider);
2056            if (mockProvider == null) {
2057                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2058            }
2059            mockProvider.setStatus(status, extras, updateTime);
2060        }
2061    }
2062
2063    @Override
2064    public void clearTestProviderStatus(String provider) {
2065        checkMockPermissionsSafe();
2066        synchronized (mLock) {
2067            MockProvider mockProvider = mMockProviders.get(provider);
2068            if (mockProvider == null) {
2069                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2070            }
2071            mockProvider.clearStatus();
2072        }
2073    }
2074
2075    private void log(String log) {
2076        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2077            Slog.d(TAG, log);
2078        }
2079    }
2080
2081    @Override
2082    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2083        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2084                != PackageManager.PERMISSION_GRANTED) {
2085            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2086                    + Binder.getCallingPid()
2087                    + ", uid=" + Binder.getCallingUid());
2088            return;
2089        }
2090
2091        synchronized (mLock) {
2092            pw.println("Current Location Manager state:");
2093            pw.println("  sProvidersLoaded=" + sProvidersLoaded);
2094            pw.println("  Listeners:");
2095            int N = mReceivers.size();
2096            for (int i=0; i<N; i++) {
2097                pw.println("    " + mReceivers.get(i));
2098            }
2099            pw.println("  Location Listeners:");
2100            for (Receiver i : mReceivers.values()) {
2101                pw.println("    " + i + ":");
2102                for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
2103                    pw.println("      " + j.getKey() + ":");
2104                    j.getValue().dump(pw, "        ");
2105                }
2106            }
2107            pw.println("  Records by Provider:");
2108            for (Map.Entry<String, ArrayList<UpdateRecord>> i
2109                    : mRecordsByProvider.entrySet()) {
2110                pw.println("    " + i.getKey() + ":");
2111                for (UpdateRecord j : i.getValue()) {
2112                    pw.println("      " + j + ":");
2113                    j.dump(pw, "        ");
2114                }
2115            }
2116            pw.println("  Last Known Locations:");
2117            for (Map.Entry<String, Location> i
2118                    : mLastKnownLocation.entrySet()) {
2119                pw.println("    " + i.getKey() + ":");
2120                i.getValue().dump(new PrintWriterPrinter(pw), "      ");
2121            }
2122            mGeofenceManager.dump(pw);
2123            if (mEnabledProviders.size() > 0) {
2124                pw.println("  Enabled Providers:");
2125                for (String i : mEnabledProviders) {
2126                    pw.println("    " + i);
2127                }
2128
2129            }
2130            if (mDisabledProviders.size() > 0) {
2131                pw.println("  Disabled Providers:");
2132                for (String i : mDisabledProviders) {
2133                    pw.println("    " + i);
2134                }
2135
2136            }
2137            if (mMockProviders.size() > 0) {
2138                pw.println("  Mock Providers:");
2139                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2140                    i.getValue().dump(pw, "      ");
2141                }
2142            }
2143            for (LocationProviderInterface provider: mProviders) {
2144                String state = provider.getInternalState();
2145                if (state != null) {
2146                    pw.println(provider.getName() + " Internal State:");
2147                    pw.write(state);
2148                }
2149            }
2150        }
2151    }
2152}
2153