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