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