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