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