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