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