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