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