blob: d3dcd69c66fc891d1a771738ebe3134ceb8eb1b5 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Dianne Hackborna06de0f2012-12-11 16:34:47 -080019import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070021import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070025import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070026import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050027import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070029import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050030import android.content.pm.ResolveInfo;
31import android.content.pm.Signature;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050032import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070033import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070035import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050036import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070037import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040039import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.location.ILocationListener;
41import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040042import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.location.Location;
44import android.location.LocationManager;
45import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070046import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.Binder;
48import android.os.Bundle;
49import android.os.Handler;
50import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070051import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.Message;
53import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070054import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070056import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070057import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070058import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080061import android.util.Slog;
Mike Lockwoode97ae402010-09-29 15:23:46 -040062import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070063import com.android.internal.location.ProviderProperties;
64import com.android.internal.location.ProviderRequest;
Dianne Hackborn8d044e82013-04-30 17:24:15 -070065import com.android.internal.os.BackgroundThread;
Mike Lockwood43e33f22010-03-26 10:41:48 -040066import com.android.server.location.GeocoderProxy;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070067import com.android.server.location.GeofenceProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070068import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040069import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070070import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070071import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040072import com.android.server.location.LocationProviderInterface;
73import com.android.server.location.LocationProviderProxy;
74import com.android.server.location.MockProvider;
75import com.android.server.location.PassiveProvider;
76
77import java.io.FileDescriptor;
78import java.io.PrintWriter;
79import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070080import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040081import java.util.HashMap;
82import java.util.HashSet;
83import java.util.List;
84import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040085import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
87/**
88 * The service class that manages LocationProviders and issues location
89 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 */
Victoria Lease5cd731a2012-12-19 15:04:21 -080091public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -080093 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -070094
95 private static final String WAKELOCK_KEY = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
Victoria Lease37425c32012-10-16 16:08:48 -070097 // Location resolution level: no location data whatsoever
98 private static final int RESOLUTION_LEVEL_NONE = 0;
99 // Location resolution level: coarse location data only
100 private static final int RESOLUTION_LEVEL_COARSE = 1;
101 // Location resolution level: fine location data
102 private static final int RESOLUTION_LEVEL_FINE = 2;
103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700105 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700107 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400108 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700109 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
110
111 private static final String NETWORK_LOCATION_SERVICE_ACTION =
112 "com.android.location.service.v2.NetworkLocationProvider";
113 private static final String FUSED_LOCATION_SERVICE_ACTION =
114 "com.android.location.service.FusedLocationProvider";
115
116 private static final int MSG_LOCATION_CHANGED = 1;
117
David Christie1b9b7b12013-04-15 15:31:11 -0700118 private static final long NANOS_PER_MILLI = 1000000L;
119
Nick Pellyf1be6862012-05-15 10:53:42 -0700120 // Location Providers may sometimes deliver location updates
121 // slightly faster that requested - provide grace period so
122 // we don't unnecessarily filter events that are otherwise on
123 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700124 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700125
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700126 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
127
128 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800129 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700130
131 // used internally for synchronization
132 private final Object mLock = new Object();
133
Victoria Lease5cd731a2012-12-19 15:04:21 -0800134 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700135 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700136 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700137 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700138 private PowerManager mPowerManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700139 private GeocoderProxy mGeocodeProvider;
140 private IGpsStatusProvider mGpsStatusProvider;
141 private INetInitiatedListener mNetInitiatedListener;
142 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700143 private PassiveProvider mPassiveProvider; // track passive provider for special cases
144 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700145
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700146 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 // Set of providers that are explicitly enabled
148 private final Set<String> mEnabledProviders = new HashSet<String>();
149
150 // Set of providers that are explicitly disabled
151 private final Set<String> mDisabledProviders = new HashSet<String>();
152
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700153 // Mock (test) providers
154 private final HashMap<String, MockProvider> mMockProviders =
155 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700157 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400158 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500161 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400163
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700164 // real providers, saved here when mocked out
165 private final HashMap<String, LocationProviderInterface> mRealProviders =
166 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700168 // mapping from provider name to provider
169 private final HashMap<String, LocationProviderInterface> mProvidersByName =
170 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172 // mapping from provider name to all its UpdateRecords
173 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
174 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700175
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700176 // mapping from provider name to last known location
177 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
David Christie1b9b7b12013-04-15 15:31:11 -0700179 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
180 // locations stored here are not fudged for coarse permissions.
181 private final HashMap<String, Location> mLastLocationCoarseInterval =
182 new HashMap<String, Location>();
183
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700184 // all providers that operate over proxy, for authorizing incoming location
185 private final ArrayList<LocationProviderProxy> mProxyProviders =
186 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187
Victoria Lease38389b62012-09-30 11:44:22 -0700188 // current active user on the device - other users are denied location data
189 private int mCurrentUserId = UserHandle.USER_OWNER;
190
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700191 public LocationManagerService(Context context) {
192 super();
193 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800194 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 if (D) Log.d(TAG, "Constructed");
197
198 // most startup is deferred until systemReady()
199 }
200
Svetoslav Ganova0027152013-06-25 14:59:53 -0700201 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700202 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800203 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700204
Victoria Lease5cd731a2012-12-19 15:04:21 -0800205 // fetch package manager
206 mPackageManager = mContext.getPackageManager();
207
Victoria Lease0aa28602013-05-29 15:28:26 -0700208 // fetch power manager
209 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800210
211 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700212 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800213
214 // prepare mLocationHandler's dependents
215 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
216 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
217 mBlacklist.init();
218 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
219
Dianne Hackbornc2293022013-02-06 23:14:49 -0800220 // Monitor for app ops mode changes.
221 AppOpsManager.Callback callback = new AppOpsManager.Callback() {
222 public void opChanged(int op, String packageName) {
223 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700224 for (Receiver receiver : mReceivers.values()) {
225 receiver.updateMonitoring(true);
226 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800227 applyAllProviderRequirementsLocked();
228 }
229 }
230 };
231 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
232
Victoria Lease5cd731a2012-12-19 15:04:21 -0800233 // prepare providers
234 loadProvidersLocked();
235 updateProvidersLocked();
236 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700237
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700238 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700239 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700240 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700241 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800242 @Override
243 public void onChange(boolean selfChange) {
244 synchronized (mLock) {
245 updateProvidersLocked();
246 }
247 }
248 }, UserHandle.USER_ALL);
249 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700250
Victoria Lease38389b62012-09-30 11:44:22 -0700251 // listen for user change
252 IntentFilter intentFilter = new IntentFilter();
253 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
254
255 mContext.registerReceiverAsUser(new BroadcastReceiver() {
256 @Override
257 public void onReceive(Context context, Intent intent) {
258 String action = intent.getAction();
259 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
260 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
261 }
262 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800263 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700264 }
265
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500266 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
267 PackageManager pm = mContext.getPackageManager();
268 String systemPackageName = mContext.getPackageName();
269 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
270
271 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
272 new Intent(FUSED_LOCATION_SERVICE_ACTION),
273 PackageManager.GET_META_DATA, mCurrentUserId);
274 for (ResolveInfo rInfo : rInfos) {
275 String packageName = rInfo.serviceInfo.packageName;
276
277 // Check that the signature is in the list of supported sigs. If it's not in
278 // this list the standard provider binding logic won't bind to it.
279 try {
280 PackageInfo pInfo;
281 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
282 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
283 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
284 ", but has wrong signature, ignoring");
285 continue;
286 }
287 } catch (NameNotFoundException e) {
288 Log.e(TAG, "missing package: " + packageName);
289 continue;
290 }
291
292 // Get the version info
293 if (rInfo.serviceInfo.metaData == null) {
294 Log.w(TAG, "Found fused provider without metadata: " + packageName);
295 continue;
296 }
297
298 int version = rInfo.serviceInfo.metaData.getInt(
299 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
300 if (version == 0) {
301 // This should be the fallback fused location provider.
302
303 // Make sure it's in the system partition.
304 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
305 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
306 continue;
307 }
308
309 // Check that the fallback is signed the same as the OS
310 // as a proxy for coreApp="true"
311 if (pm.checkSignatures(systemPackageName, packageName)
312 != PackageManager.SIGNATURE_MATCH) {
313 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
314 + packageName);
315 continue;
316 }
317
318 // Found a valid fallback.
319 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
320 return;
321 } else {
322 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
323 }
324 }
325
326 throw new IllegalStateException("Unable to find a fused location provider that is in the "
327 + "system partition with version 0 and signed with the platform certificate. "
328 + "Such a package is needed to provide a default fused location provider in the "
329 + "event that no other fused location provider has been installed or is currently "
330 + "available. For example, coreOnly boot mode when decrypting the data "
331 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
332 }
333
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700334 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700335 // create a passive location provider, which is always enabled
336 PassiveProvider passiveProvider = new PassiveProvider(this);
337 addProviderLocked(passiveProvider);
338 mEnabledProviders.add(passiveProvider.getName());
339 mPassiveProvider = passiveProvider;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700340 // Create a gps location provider
341 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
342 mLocationHandler.getLooper());
Victoria Lease5c24fd02012-10-01 11:00:50 -0700343
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700344 if (GpsLocationProvider.isSupported()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700345 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
346 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
347 addProviderLocked(gpsProvider);
348 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
349 }
350
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700351 /*
352 Load package name(s) containing location provider support.
353 These packages can contain services implementing location providers:
354 Geocoder Provider, Network Location Provider, and
355 Fused Location Provider. They will each be searched for
356 service components implementing these providers.
357 The location framework also has support for installation
358 of new location providers at run-time. The new package does not
359 have to be explicitly listed here, however it must have a signature
360 that matches the signature of at least one package on this list.
361 */
362 Resources resources = mContext.getResources();
363 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500364 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700365 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500366 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
367 Arrays.toString(pkgs));
368 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
369
370 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700371
372 // bind to network provider
373 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
374 mContext,
375 LocationManager.NETWORK_PROVIDER,
376 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700377 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
378 com.android.internal.R.string.config_networkLocationProviderPackageName,
379 com.android.internal.R.array.config_locationProviderPackageNames,
380 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700381 if (networkProvider != null) {
382 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
383 mProxyProviders.add(networkProvider);
384 addProviderLocked(networkProvider);
385 } else {
386 Slog.w(TAG, "no network location provider found");
387 }
388
389 // bind to fused provider
390 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
391 mContext,
392 LocationManager.FUSED_PROVIDER,
393 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700394 com.android.internal.R.bool.config_enableFusedLocationOverlay,
395 com.android.internal.R.string.config_fusedLocationProviderPackageName,
396 com.android.internal.R.array.config_locationProviderPackageNames,
397 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700398 if (fusedLocationProvider != null) {
399 addProviderLocked(fusedLocationProvider);
400 mProxyProviders.add(fusedLocationProvider);
401 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700402 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700403 } else {
404 Slog.e(TAG, "no fused location provider found",
405 new IllegalStateException("Location service needs a fused location provider"));
406 }
407
408 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700409 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
410 com.android.internal.R.bool.config_enableGeocoderOverlay,
411 com.android.internal.R.string.config_geocoderProviderPackageName,
412 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800413 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700414 if (mGeocodeProvider == null) {
415 Slog.e(TAG, "no geocoder provider found");
416 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700417
418 // bind to geofence provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700419 GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
420 com.android.internal.R.bool.config_enableGeofenceOverlay,
421 com.android.internal.R.string.config_geofenceProviderPackageName,
422 com.android.internal.R.array.config_locationProviderPackageNames,
423 mLocationHandler,
424 gpsProvider.getGpsGeofenceProxy());
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700425 if (provider == null) {
426 Slog.e(TAG, "no geofence provider found");
427 }
428
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700429 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700432 * Called when the device's active user changes.
433 * @param userId the new active user's UserId
434 */
435 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700436 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800437 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700438 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700439 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700440 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700441 for (LocationProviderInterface p : mProviders) {
442 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700443 }
Victoria Lease38389b62012-09-30 11:44:22 -0700444 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700445 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700446 }
447 }
448
449 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
451 * location updates.
452 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700453 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700454 final int mUid; // uid of receiver
455 final int mPid; // pid of receiver
456 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700457 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 final ILocationListener mListener;
460 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700461 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700463
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400464 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700465
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700466 boolean mOpMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700467 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700468 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700470 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie82edc9b2013-07-19 11:31:42 -0700471 String packageName, WorkSource workSource) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700474 if (listener != null) {
475 mKey = listener.asBinder();
476 } else {
477 mKey = intent;
478 }
Victoria Lease37425c32012-10-16 16:08:48 -0700479 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700480 mUid = uid;
481 mPid = pid;
482 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700483 if (workSource != null && workSource.size() <= 0) {
484 workSource = null;
485 }
486 mWorkSource = workSource;
Victoria Lease0aa28602013-05-29 15:28:26 -0700487
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700488 updateMonitoring(true);
489
Victoria Lease0aa28602013-05-29 15:28:26 -0700490 // construct/configure wakelock
491 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700492 if (workSource == null) {
493 workSource = new WorkSource(mUid, mPackageName);
494 }
495 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 }
497
498 @Override
499 public boolean equals(Object otherObj) {
500 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700501 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 }
503 return false;
504 }
505
506 @Override
507 public int hashCode() {
508 return mKey.hashCode();
509 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 @Override
512 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700513 StringBuilder s = new StringBuilder();
514 s.append("Reciever[");
515 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700517 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700519 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700521 for (String p : mUpdateRecords.keySet()) {
522 s.append(" ").append(mUpdateRecords.get(p).toString());
523 }
524 s.append("]");
525 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 }
527
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700528 public void updateMonitoring(boolean allow) {
529 if (!mOpMonitoring) {
530 if (allow) {
531 mOpMonitoring = mAppOps.startOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
532 mUid, mPackageName) == AppOpsManager.MODE_ALLOWED;
533 }
534 } else {
535 if (!allow || mAppOps.checkOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
536 mUid, mPackageName) != AppOpsManager.MODE_ALLOWED) {
537 mAppOps.finishOp(AppOpsManager.OP_MONITOR_LOCATION, mUid, mPackageName);
538 mOpMonitoring = false;
539 }
540 }
541 }
542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 public boolean isListener() {
544 return mListener != null;
545 }
546
547 public boolean isPendingIntent() {
548 return mPendingIntent != null;
549 }
550
551 public ILocationListener getListener() {
552 if (mListener != null) {
553 return mListener;
554 }
555 throw new IllegalStateException("Request for non-existent listener");
556 }
557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
559 if (mListener != null) {
560 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700561 synchronized (this) {
562 // synchronize to ensure incrementPendingBroadcastsLocked()
563 // is called before decrementPendingBroadcasts()
564 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700565 // call this after broadcasting so we do not increment
566 // if we throw an exeption.
567 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 } catch (RemoteException e) {
570 return false;
571 }
572 } else {
573 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800574 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
576 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700577 synchronized (this) {
578 // synchronize to ensure incrementPendingBroadcastsLocked()
579 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700580 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700581 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700582 // call this after broadcasting so we do not increment
583 // if we throw an exeption.
584 incrementPendingBroadcastsLocked();
585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 } catch (PendingIntent.CanceledException e) {
587 return false;
588 }
589 }
590 return true;
591 }
592
593 public boolean callLocationChangedLocked(Location location) {
594 if (mListener != null) {
595 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700596 synchronized (this) {
597 // synchronize to ensure incrementPendingBroadcastsLocked()
598 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800599 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700600 // call this after broadcasting so we do not increment
601 // if we throw an exeption.
602 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 } catch (RemoteException e) {
605 return false;
606 }
607 } else {
608 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800609 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700611 synchronized (this) {
612 // synchronize to ensure incrementPendingBroadcastsLocked()
613 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700614 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700615 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700616 // call this after broadcasting so we do not increment
617 // if we throw an exeption.
618 incrementPendingBroadcastsLocked();
619 }
620 } catch (PendingIntent.CanceledException e) {
621 return false;
622 }
623 }
624 return true;
625 }
626
627 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
628 if (mListener != null) {
629 try {
630 synchronized (this) {
631 // synchronize to ensure incrementPendingBroadcastsLocked()
632 // is called before decrementPendingBroadcasts()
633 if (enabled) {
634 mListener.onProviderEnabled(provider);
635 } else {
636 mListener.onProviderDisabled(provider);
637 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700638 // call this after broadcasting so we do not increment
639 // if we throw an exeption.
640 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700641 }
642 } catch (RemoteException e) {
643 return false;
644 }
645 } else {
646 Intent providerIntent = new Intent();
647 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
648 try {
649 synchronized (this) {
650 // synchronize to ensure incrementPendingBroadcastsLocked()
651 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700652 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700653 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700654 // call this after broadcasting so we do not increment
655 // if we throw an exeption.
656 incrementPendingBroadcastsLocked();
657 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 } catch (PendingIntent.CanceledException e) {
659 return false;
660 }
661 }
662 return true;
663 }
664
Nick Pellyf1be6862012-05-15 10:53:42 -0700665 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700667 if (D) Log.d(TAG, "Location listener died");
668
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400669 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 removeUpdatesLocked(this);
671 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700672 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700673 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700674 }
675 }
676
Nick Pellye0fd6932012-07-11 10:26:13 -0700677 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700678 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
679 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400680 synchronized (this) {
681 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700682 }
683 }
684
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400685 // this must be called while synchronized by caller in a synchronized block
686 // containing the sending of the broadcaset
687 private void incrementPendingBroadcastsLocked() {
688 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700689 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400690 }
691 }
692
693 private void decrementPendingBroadcastsLocked() {
694 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700695 if (mWakeLock.isHeld()) {
696 mWakeLock.release();
697 }
698 }
699 }
700
701 public void clearPendingBroadcastsLocked() {
702 if (mPendingBroadcasts > 0) {
703 mPendingBroadcasts = 0;
704 if (mWakeLock.isHeld()) {
705 mWakeLock.release();
706 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700707 }
708 }
709 }
710
Nick Pellye0fd6932012-07-11 10:26:13 -0700711 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700712 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700713 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400714 //the receiver list if it is not found. If it is not found then the
715 //LocationListener was removed when it had a pending broadcast and should
716 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700717 synchronized (mLock) {
718 IBinder binder = listener.asBinder();
719 Receiver receiver = mReceivers.get(binder);
720 if (receiver != null) {
721 synchronized (receiver) {
722 // so wakelock calls will succeed
723 long identity = Binder.clearCallingIdentity();
724 receiver.decrementPendingBroadcastsLocked();
725 Binder.restoreCallingIdentity(identity);
726 }
727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 }
729 }
730
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700731 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400732 mProviders.add(provider);
733 mProvidersByName.put(provider.getName(), provider);
734 }
735
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700736 private void removeProviderLocked(LocationProviderInterface provider) {
737 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400738 mProviders.remove(provider);
739 mProvidersByName.remove(provider.getName());
740 }
741
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800742 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800743 * Returns "true" if access to the specified location provider is allowed by the current
744 * user's settings. Access to all location providers is forbidden to non-location-provider
745 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800746 *
747 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800748 * @return
749 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800750 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 if (mEnabledProviders.contains(provider)) {
752 return true;
753 }
754 if (mDisabledProviders.contains(provider)) {
755 return false;
756 }
757 // Use system settings
758 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759
Victoria Leaseb711d572012-10-02 13:14:11 -0700760 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 }
762
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700763 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800764 * Returns "true" if access to the specified location provider is allowed by the specified
765 * user's settings. Access to all location providers is forbidden to non-location-provider
766 * processes belonging to background users.
767 *
768 * @param provider the name of the location provider
769 * @param uid the requestor's UID
770 * @return
771 */
772 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
773 if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) {
774 return false;
775 }
776 return isAllowedByCurrentUserSettingsLocked(provider);
777 }
778
779 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700780 * Returns the permission string associated with the specified resolution level.
781 *
782 * @param resolutionLevel the resolution level
783 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700784 */
Victoria Lease37425c32012-10-16 16:08:48 -0700785 private String getResolutionPermission(int resolutionLevel) {
786 switch (resolutionLevel) {
787 case RESOLUTION_LEVEL_FINE:
788 return android.Manifest.permission.ACCESS_FINE_LOCATION;
789 case RESOLUTION_LEVEL_COARSE:
790 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
791 default:
792 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700794 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700795
Victoria Leaseda479c52012-10-15 15:24:16 -0700796 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700797 * Returns the resolution level allowed to the given PID/UID pair.
798 *
799 * @param pid the PID
800 * @param uid the UID
801 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700802 */
Victoria Lease37425c32012-10-16 16:08:48 -0700803 private int getAllowedResolutionLevel(int pid, int uid) {
804 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
805 pid, uid) == PackageManager.PERMISSION_GRANTED) {
806 return RESOLUTION_LEVEL_FINE;
807 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
808 pid, uid) == PackageManager.PERMISSION_GRANTED) {
809 return RESOLUTION_LEVEL_COARSE;
810 } else {
811 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700812 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700813 }
814
815 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700816 * Returns the resolution level allowed to the caller
817 *
818 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700819 */
Victoria Lease37425c32012-10-16 16:08:48 -0700820 private int getCallerAllowedResolutionLevel() {
821 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
822 }
823
824 /**
825 * Throw SecurityException if specified resolution level is insufficient to use geofences.
826 *
827 * @param allowedResolutionLevel resolution level allowed to caller
828 */
829 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
830 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700831 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
832 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 }
834
Victoria Lease37425c32012-10-16 16:08:48 -0700835 /**
836 * Return the minimum resolution level required to use the specified location provider.
837 *
838 * @param provider the name of the location provider
839 * @return minimum resolution level required for provider
840 */
841 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700842 if (LocationManager.GPS_PROVIDER.equals(provider) ||
843 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
844 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700845 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700846 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
847 LocationManager.FUSED_PROVIDER.equals(provider)) {
848 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700849 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700850 } else {
851 // mock providers
852 LocationProviderInterface lp = mMockProviders.get(provider);
853 if (lp != null) {
854 ProviderProperties properties = lp.getProperties();
855 if (properties != null) {
856 if (properties.mRequiresSatellite) {
857 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700858 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700859 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
860 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700861 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700862 }
863 }
864 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700865 }
Victoria Lease37425c32012-10-16 16:08:48 -0700866 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700867 }
868
Victoria Lease37425c32012-10-16 16:08:48 -0700869 /**
870 * Throw SecurityException if specified resolution level is insufficient to use the named
871 * location provider.
872 *
873 * @param allowedResolutionLevel resolution level allowed to caller
874 * @param providerName the name of the location provider
875 */
876 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
877 String providerName) {
878 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
879 if (allowedResolutionLevel < requiredResolutionLevel) {
880 switch (requiredResolutionLevel) {
881 case RESOLUTION_LEVEL_FINE:
882 throw new SecurityException("\"" + providerName + "\" location provider " +
883 "requires ACCESS_FINE_LOCATION permission.");
884 case RESOLUTION_LEVEL_COARSE:
885 throw new SecurityException("\"" + providerName + "\" location provider " +
886 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
887 default:
888 throw new SecurityException("Insufficient permission for \"" + providerName +
889 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700890 }
891 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700892 }
893
David Christie82edc9b2013-07-19 11:31:42 -0700894 /**
895 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
896 * for battery).
897 */
898 private void checkWorkSourceAllowed() {
899 mContext.enforceCallingOrSelfPermission(
900 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
901 }
902
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800903 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800904 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
905 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800906 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800907 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800908 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800909 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800910 }
911 return -1;
912 }
913
914 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
915 int op = resolutionLevelToOp(allowedResolutionLevel);
916 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800917 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
918 return false;
919 }
920 }
921 return true;
922 }
923
924 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800925 int op = resolutionLevelToOp(allowedResolutionLevel);
926 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800927 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
928 return false;
929 }
930 }
931 return true;
932 }
933
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700934 /**
935 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700936 * fused, also including ones that are not permitted to
937 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700938 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700939 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700941 ArrayList<String> out;
942 synchronized (mLock) {
943 out = new ArrayList<String>(mProviders.size());
944 for (LocationProviderInterface provider : mProviders) {
945 String name = provider.getName();
946 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700947 continue;
948 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 out.add(name);
950 }
951 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700952
953 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 return out;
955 }
956
Mike Lockwood03ca2162010-04-01 08:10:09 -0700957 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700958 * Return all providers by name, that match criteria and are optionally
959 * enabled.
960 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700961 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700962 @Override
963 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700964 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700965 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800966 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -0700967 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700968 try {
969 synchronized (mLock) {
970 out = new ArrayList<String>(mProviders.size());
971 for (LocationProviderInterface provider : mProviders) {
972 String name = provider.getName();
973 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700974 continue;
975 }
Victoria Lease37425c32012-10-16 16:08:48 -0700976 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -0800977 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700978 continue;
979 }
980 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
981 name, provider.getProperties(), criteria)) {
982 continue;
983 }
984 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700985 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700986 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700987 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700988 } finally {
989 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700990 }
991
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700992 if (D) Log.d(TAG, "getProviders()=" + out);
993 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700994 }
995
996 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700997 * Return the name of the best provider given a Criteria object.
998 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700999 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001000 * has been deprecated as well. So this method now uses
1001 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001002 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001003 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001004 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001005 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001006
1007 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001008 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001009 result = pickBest(providers);
1010 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1011 return result;
1012 }
1013 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001014 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001015 result = pickBest(providers);
1016 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1017 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001018 }
1019
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001020 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001021 return null;
1022 }
1023
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001024 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001025 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001026 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001027 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1028 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001029 } else {
1030 return providers.get(0);
1031 }
1032 }
1033
Nick Pellye0fd6932012-07-11 10:26:13 -07001034 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001035 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1036 LocationProviderInterface p = mProvidersByName.get(provider);
1037 if (p == null) {
1038 throw new IllegalArgumentException("provider=" + provider);
1039 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001040
1041 boolean result = LocationProvider.propertiesMeetCriteria(
1042 p.getName(), p.getProperties(), criteria);
1043 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1044 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001045 }
1046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001048 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001049 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001050 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 boolean isEnabled = p.isEnabled();
1052 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001053 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001055 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001056 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001058 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001059 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001061 }
1062 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001063 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1064 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 }
1066 }
1067
Victoria Leaseb711d572012-10-02 13:14:11 -07001068 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 int listeners = 0;
1070
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001071 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001072 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073
1074 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1077 if (records != null) {
1078 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001079 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -07001081 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001082 // Sends a notification message to the receiver
1083 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1084 if (deadReceivers == null) {
1085 deadReceivers = new ArrayList<Receiver>();
1086 }
1087 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001089 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 }
1092 }
1093
1094 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001095 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 removeUpdatesLocked(deadReceivers.get(i));
1097 }
1098 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 if (enabled) {
1101 p.enable();
1102 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001103 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 }
1105 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 }
1109
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001110 private void applyRequirementsLocked(String provider) {
1111 LocationProviderInterface p = mProvidersByName.get(provider);
1112 if (p == null) return;
1113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001115 WorkSource worksource = new WorkSource();
1116 ProviderRequest providerRequest = new ProviderRequest();
1117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001119 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001120 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001121 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1122 record.mReceiver.mAllowedResolutionLevel)) {
1123 LocationRequest locationRequest = record.mRequest;
1124 providerRequest.locationRequests.add(locationRequest);
1125 if (locationRequest.getInterval() < providerRequest.interval) {
1126 providerRequest.reportLocation = true;
1127 providerRequest.interval = locationRequest.getInterval();
1128 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001129 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001130 }
1131 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001132
1133 if (providerRequest.reportLocation) {
1134 // calculate who to blame for power
1135 // This is somewhat arbitrary. We pick a threshold interval
1136 // that is slightly higher that the minimum interval, and
1137 // spread the blame across all applications with a request
1138 // under that threshold.
1139 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1140 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001141 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001142 LocationRequest locationRequest = record.mRequest;
1143 if (locationRequest.getInterval() <= thresholdInterval) {
David Christie82edc9b2013-07-19 11:31:42 -07001144 if (record.mReceiver.mWorkSource != null) {
1145 // Assign blame to another work source.
1146 worksource.add(record.mReceiver.mWorkSource);
1147 } else {
1148 // Assign blame to caller.
1149 worksource.add(
1150 record.mReceiver.mUid,
1151 record.mReceiver.mPackageName);
1152 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001153 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001154 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 }
1157 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001158
1159 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1160 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 }
1162
1163 private class UpdateRecord {
1164 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001165 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001167 Location mLastFixBroadcast;
1168 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169
1170 /**
1171 * Note: must be constructed with lock held.
1172 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001173 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001175 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177
1178 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1179 if (records == null) {
1180 records = new ArrayList<UpdateRecord>();
1181 mRecordsByProvider.put(provider, records);
1182 }
1183 if (!records.contains(this)) {
1184 records.add(this);
1185 }
1186 }
1187
1188 /**
1189 * Method to be called when a record will no longer be used. Calling this multiple times
1190 * must have the same effect as calling it once.
1191 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001192 void disposeLocked(boolean removeReceiver) {
1193 // remove from mRecordsByProvider
1194 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1195 if (globalRecords != null) {
1196 globalRecords.remove(this);
1197 }
1198
1199 if (!removeReceiver) return; // the caller will handle the rest
1200
1201 // remove from Receiver#mUpdateRecords
1202 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1203 if (receiverRecords != null) {
1204 receiverRecords.remove(this.mProvider);
1205
1206 // and also remove the Receiver if it has no more update records
1207 if (removeReceiver && receiverRecords.size() == 0) {
1208 removeUpdatesLocked(mReceiver);
1209 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001210 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 }
1212
1213 @Override
1214 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001215 StringBuilder s = new StringBuilder();
1216 s.append("UpdateRecord[");
1217 s.append(mProvider);
1218 s.append(' ').append(mReceiver.mPackageName).append('(');
1219 s.append(mReceiver.mUid).append(')');
1220 s.append(' ').append(mRequest);
1221 s.append(']');
1222 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 }
1225
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001226 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie82edc9b2013-07-19 11:31:42 -07001227 String packageName, WorkSource workSource) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001228 IBinder binder = listener.asBinder();
1229 Receiver receiver = mReceivers.get(binder);
1230 if (receiver == null) {
David Christie82edc9b2013-07-19 11:31:42 -07001231 receiver = new Receiver(listener, null, pid, uid, packageName, workSource);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001232 mReceivers.put(binder, receiver);
1233
1234 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001235 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001236 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001237 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001238 return null;
1239 }
1240 }
1241 return receiver;
1242 }
1243
David Christie82edc9b2013-07-19 11:31:42 -07001244 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
1245 WorkSource workSource) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001246 Receiver receiver = mReceivers.get(intent);
1247 if (receiver == null) {
David Christie82edc9b2013-07-19 11:31:42 -07001248 receiver = new Receiver(null, intent, pid, uid, packageName, workSource);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001249 mReceivers.put(intent, receiver);
1250 }
1251 return receiver;
1252 }
1253
Victoria Lease37425c32012-10-16 16:08:48 -07001254 /**
1255 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1256 * and consistency requirements.
1257 *
1258 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001259 * @return a version of request that meets the given resolution and consistency requirements
1260 * @hide
1261 */
1262 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1263 LocationRequest sanitizedRequest = new LocationRequest(request);
1264 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1265 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001266 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001267 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001268 break;
1269 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001270 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001271 break;
1272 }
1273 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001274 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1275 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001276 }
Victoria Lease37425c32012-10-16 16:08:48 -07001277 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1278 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001279 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001280 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001281 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001282 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001283 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001284 }
Victoria Lease37425c32012-10-16 16:08:48 -07001285 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001286 }
1287
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001288 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001289 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001290 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001291 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001292 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001293 String[] packages = mPackageManager.getPackagesForUid(uid);
1294 if (packages == null) {
1295 throw new SecurityException("invalid UID " + uid);
1296 }
1297 for (String pkg : packages) {
1298 if (packageName.equals(pkg)) return;
1299 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001300 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001301 }
1302
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001303 private void checkPendingIntent(PendingIntent intent) {
1304 if (intent == null) {
1305 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001306 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001307 }
1308
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001309 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie82edc9b2013-07-19 11:31:42 -07001310 int pid, int uid, String packageName, WorkSource workSource) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001311 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001312 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001313 } else if (intent != null && listener != null) {
1314 throw new IllegalArgumentException("cannot register both listener and intent");
1315 } else if (intent != null) {
1316 checkPendingIntent(intent);
David Christie82edc9b2013-07-19 11:31:42 -07001317 return getReceiverLocked(intent, pid, uid, packageName, workSource);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001318 } else {
David Christie82edc9b2013-07-19 11:31:42 -07001319 return getReceiverLocked(listener, pid, uid, packageName, workSource);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001320 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001321 }
1322
Nick Pellye0fd6932012-07-11 10:26:13 -07001323 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1325 PendingIntent intent, String packageName) {
1326 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1327 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001328 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1329 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1330 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001331 WorkSource workSource = request.getWorkSource();
1332 if (workSource != null && workSource.size() > 0) {
1333 checkWorkSourceAllowed();
1334 }
Victoria Lease37425c32012-10-16 16:08:48 -07001335 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001337 final int pid = Binder.getCallingPid();
1338 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001339 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340 long identity = Binder.clearCallingIdentity();
1341 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001342 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1343 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001344 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001345
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001346 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001347 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie82edc9b2013-07-19 11:31:42 -07001348 packageName, workSource);
Victoria Lease37425c32012-10-16 16:08:48 -07001349 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 } finally {
1352 Binder.restoreCallingIdentity(identity);
1353 }
1354 }
1355
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001356 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1357 int pid, int uid, String packageName) {
1358 // Figure out the provider. Either its explicitly request (legacy use cases), or
1359 // use the fused provider
1360 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1361 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001362 if (name == null) {
1363 throw new IllegalArgumentException("provider name must not be null");
1364 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001365
1366 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1367 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001368 LocationProviderInterface provider = mProvidersByName.get(name);
1369 if (provider == null) {
1370 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1371 }
1372
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001373 UpdateRecord record = new UpdateRecord(name, request, receiver);
1374 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1375 if (oldRecord != null) {
1376 oldRecord.disposeLocked(false);
1377 }
1378
Victoria Lease09eeaec2013-02-05 11:34:13 -08001379 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001380 if (isProviderEnabled) {
1381 applyRequirementsLocked(name);
1382 } else {
1383 // Notify the listener that updates are currently disabled
1384 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 }
1386 }
1387
Nick Pellye0fd6932012-07-11 10:26:13 -07001388 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001389 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1390 String packageName) {
1391 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001392
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001393 final int pid = Binder.getCallingPid();
1394 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001395
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001396 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07001397 WorkSource workSource = null;
1398 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, packageName,
1399 workSource);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001400
1401 // providers may use public location API's, need to clear identity
1402 long identity = Binder.clearCallingIdentity();
1403 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001404 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001405 } finally {
1406 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001407 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 }
1409 }
1410
1411 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001412 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001413
1414 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1415 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1416 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001417 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001418 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 }
1420
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001421 receiver.updateMonitoring(false);
1422
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001423 // Record which providers were associated with this listener
1424 HashSet<String> providers = new HashSet<String>();
1425 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1426 if (oldRecords != null) {
1427 // Call dispose() on the obsolete update records.
1428 for (UpdateRecord record : oldRecords.values()) {
1429 record.disposeLocked(false);
1430 }
1431 // Accumulate providers
1432 providers.addAll(oldRecords.keySet());
1433 }
1434
1435 // update provider
1436 for (String provider : providers) {
1437 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001438 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001439 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 }
1441
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001442 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 }
1444 }
1445
Dianne Hackbornc2293022013-02-06 23:14:49 -08001446 private void applyAllProviderRequirementsLocked() {
1447 for (LocationProviderInterface p : mProviders) {
1448 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001449 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001450 continue;
1451 }
1452
1453 applyRequirementsLocked(p.getName());
1454 }
1455 }
1456
Nick Pellye0fd6932012-07-11 10:26:13 -07001457 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001458 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001459 if (D) Log.d(TAG, "getLastLocation: " + request);
1460 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001461 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001462 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001463 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1464 request.getProvider());
1465 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001466
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001467 final int uid = Binder.getCallingUid();
1468 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001469 try {
1470 if (mBlacklist.isBlacklisted(packageName)) {
1471 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1472 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001473 return null;
1474 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001475
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001476 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1477 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1478 packageName);
1479 return null;
1480 }
1481
Victoria Leaseb711d572012-10-02 13:14:11 -07001482 synchronized (mLock) {
1483 // Figure out the provider. Either its explicitly request (deprecated API's),
1484 // or use the fused provider
1485 String name = request.getProvider();
1486 if (name == null) name = LocationManager.FUSED_PROVIDER;
1487 LocationProviderInterface provider = mProvidersByName.get(name);
1488 if (provider == null) return null;
1489
Victoria Lease09eeaec2013-02-05 11:34:13 -08001490 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001491
David Christie1b9b7b12013-04-15 15:31:11 -07001492 Location location;
1493 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1494 // Make sure that an app with coarse permissions can't get frequent location
1495 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1496 location = mLastLocationCoarseInterval.get(name);
1497 } else {
1498 location = mLastLocation.get(name);
1499 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001500 if (location == null) {
1501 return null;
1502 }
Victoria Lease37425c32012-10-16 16:08:48 -07001503 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001504 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1505 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001506 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001507 }
Victoria Lease37425c32012-10-16 16:08:48 -07001508 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001509 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001510 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001511 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001512 return null;
1513 } finally {
1514 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001515 }
1516 }
1517
1518 @Override
1519 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1520 String packageName) {
1521 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001522 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1523 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001524 checkPendingIntent(intent);
1525 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001526 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1527 request.getProvider());
1528 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001529
Victoria Lease37425c32012-10-16 16:08:48 -07001530 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001531
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001532 // geo-fence manager uses the public location API, need to clear identity
1533 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001534 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1535 // temporary measure until geofences work for secondary users
1536 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1537 return;
1538 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001539 long identity = Binder.clearCallingIdentity();
1540 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001541 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1542 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001543 } finally {
1544 Binder.restoreCallingIdentity(identity);
1545 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001546 }
1547
1548 @Override
1549 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001550 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001551 checkPendingIntent(intent);
1552 checkPackageName(packageName);
1553
1554 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1555
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001556 // geo-fence manager uses the public location API, need to clear identity
1557 long identity = Binder.clearCallingIdentity();
1558 try {
1559 mGeofenceManager.removeFence(geofence, intent);
1560 } finally {
1561 Binder.restoreCallingIdentity(identity);
1562 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001563 }
1564
1565
1566 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001567 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001568 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 return false;
1570 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001571 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1572 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001573 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001575 final int uid = Binder.getCallingUid();
1576 final long ident = Binder.clearCallingIdentity();
1577 try {
Victoria Lease3d5173d2013-02-05 16:07:32 -08001578 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001579 return false;
1580 }
1581 } finally {
1582 Binder.restoreCallingIdentity(ident);
1583 }
1584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001586 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001588 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001589 return false;
1590 }
1591 return true;
1592 }
1593
Nick Pellye0fd6932012-07-11 10:26:13 -07001594 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001596 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001597 try {
1598 mGpsStatusProvider.removeGpsStatusListener(listener);
1599 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001600 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001601 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 }
1603 }
1604
Nick Pellye0fd6932012-07-11 10:26:13 -07001605 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001607 if (provider == null) {
1608 // throw NullPointerException to remain compatible with previous implementation
1609 throw new NullPointerException();
1610 }
Victoria Lease37425c32012-10-16 16:08:48 -07001611 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1612 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001615 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 != PackageManager.PERMISSION_GRANTED)) {
1617 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1618 }
1619
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001620 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001621 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001622 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001623
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001624 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 }
1626 }
1627
Nick Pellye0fd6932012-07-11 10:26:13 -07001628 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001629 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001630 if (Binder.getCallingUid() != Process.myUid()) {
1631 throw new SecurityException(
1632 "calling sendNiResponse from outside of the system is not allowed");
1633 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001634 try {
1635 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001636 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001637 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001638 return false;
1639 }
1640 }
1641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001643 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001644 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 * accessed by the caller
1646 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001647 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001648 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001649 if (mProvidersByName.get(provider) == null) {
1650 return null;
1651 }
1652
Victoria Lease37425c32012-10-16 16:08:48 -07001653 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1654 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001656 LocationProviderInterface p;
1657 synchronized (mLock) {
1658 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 }
1660
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001661 if (p == null) return null;
1662 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 }
1664
Nick Pellye0fd6932012-07-11 10:26:13 -07001665 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001667 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1668 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001669 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1670
Victoria Lease09eeaec2013-02-05 11:34:13 -08001671 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001672 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001673 try {
1674 synchronized (mLock) {
1675 LocationProviderInterface p = mProvidersByName.get(provider);
1676 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001677
Victoria Lease09eeaec2013-02-05 11:34:13 -08001678 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001679 }
1680 } finally {
1681 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001682 }
1683 }
1684
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001685 /**
1686 * Returns "true" if the UID belongs to a bound location provider.
1687 *
1688 * @param uid the uid
1689 * @return true if uid belongs to a bound location provider
1690 */
1691 private boolean isUidALocationProvider(int uid) {
1692 if (uid == Process.SYSTEM_UID) {
1693 return true;
1694 }
1695 if (mGeocodeProvider != null) {
1696 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1697 }
1698 for (LocationProviderProxy proxy : mProxyProviders) {
1699 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
1700 }
1701 return false;
1702 }
1703
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001704 private void checkCallerIsProvider() {
1705 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1706 == PackageManager.PERMISSION_GRANTED) {
1707 return;
1708 }
1709
1710 // Previously we only used the INSTALL_LOCATION_PROVIDER
1711 // check. But that is system or signature
1712 // protection level which is not flexible enough for
1713 // providers installed oustide the system image. So
1714 // also allow providers with a UID matching the
1715 // currently bound package name
1716
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001717 if (isUidALocationProvider(Binder.getCallingUid())) {
1718 return;
1719 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001720
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001721 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1722 "or UID of a currently bound location provider");
1723 }
1724
1725 private boolean doesPackageHaveUid(int uid, String packageName) {
1726 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 return false;
1728 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001729 try {
1730 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1731 if (appInfo.uid != uid) {
1732 return false;
1733 }
1734 } catch (NameNotFoundException e) {
1735 return false;
1736 }
1737 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 }
1739
Nick Pellye0fd6932012-07-11 10:26:13 -07001740 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001741 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001742 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001743
Nick Pelly2eeeec22012-07-18 13:13:37 -07001744 if (!location.isComplete()) {
1745 Log.w(TAG, "Dropping incomplete location: " + location);
1746 return;
1747 }
1748
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001749 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1750 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001751 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001752 mLocationHandler.sendMessageAtFrontOfQueue(m);
1753 }
1754
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755
Laurent Tu75defb62012-11-01 16:21:52 -07001756 private static boolean shouldBroadcastSafe(
1757 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 // Always broadcast the first update
1759 if (lastLoc == null) {
1760 return true;
1761 }
1762
Nick Pellyf1be6862012-05-15 10:53:42 -07001763 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001764 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07001765 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
1766 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001767 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 return false;
1769 }
1770
1771 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001772 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 if (minDistance > 0.0) {
1774 if (loc.distanceTo(lastLoc) <= minDistance) {
1775 return false;
1776 }
1777 }
1778
Laurent Tu75defb62012-11-01 16:21:52 -07001779 // Check whether sufficient number of udpates is left
1780 if (record.mRequest.getNumUpdates() <= 0) {
1781 return false;
1782 }
1783
1784 // Check whether the expiry date has passed
1785 if (record.mRequest.getExpireAt() < now) {
1786 return false;
1787 }
1788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 return true;
1790 }
1791
Mike Lockwooda4903f22010-02-17 06:42:23 -05001792 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001793 if (D) Log.d(TAG, "incoming location: " + location);
1794
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001795 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001796 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797
Laurent Tu60ec50a2012-10-04 17:00:10 -07001798 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001799 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001800 if (p == null) return;
1801
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001802 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001803 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1804 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001805 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001806 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001807 lastLocation = new Location(provider);
1808 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001809 } else {
1810 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1811 if (noGPSLocation == null && lastNoGPSLocation != null) {
1812 // New location has no no-GPS location: adopt last no-GPS location. This is set
1813 // directly into location because we do not want to notify COARSE clients.
1814 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1815 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001816 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001817 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818
David Christie1b9b7b12013-04-15 15:31:11 -07001819 // Update last known coarse interval location if enough time has passed.
1820 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
1821 if (lastLocationCoarseInterval == null) {
1822 lastLocationCoarseInterval = new Location(location);
1823 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
1824 }
1825 long timeDiffNanos = location.getElapsedRealtimeNanos()
1826 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
1827 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
1828 lastLocationCoarseInterval.set(location);
1829 }
1830 // Don't ever return a coarse location that is more recent than the allowed update
1831 // interval (i.e. don't allow an app to keep registering and unregistering for
1832 // location updates to overcome the minimum interval).
1833 noGPSLocation =
1834 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1835
Laurent Tu60ec50a2012-10-04 17:00:10 -07001836 // Skip if there are no UpdateRecords for this provider.
1837 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1838 if (records == null || records.size() == 0) return;
1839
Victoria Lease09016ab2012-09-16 12:33:15 -07001840 // Fetch coarse location
1841 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07001842 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001843 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1844 }
1845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001846 // Fetch latest status update time
1847 long newStatusUpdateTime = p.getStatusUpdateTime();
1848
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001849 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 Bundle extras = new Bundle();
1851 int status = p.getStatus(extras);
1852
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001854 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001857 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001859 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001860
Victoria Lease269518e2012-10-29 08:25:39 -07001861 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Victoria Lease2f5b97c2013-05-07 14:22:02 -07001862 if (receiverUserId != mCurrentUserId && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001863 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001864 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001865 " (current user: " + mCurrentUserId + ", app: " +
1866 receiver.mPackageName + ")");
1867 }
1868 continue;
1869 }
1870
Nick Pelly4035f5a2012-08-17 14:43:49 -07001871 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1872 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1873 receiver.mPackageName);
1874 continue;
1875 }
1876
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001877 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
1878 receiver.mAllowedResolutionLevel)) {
1879 if (D) Log.d(TAG, "skipping loc update for no op app: " +
1880 receiver.mPackageName);
1881 continue;
1882 }
1883
Victoria Lease09016ab2012-09-16 12:33:15 -07001884 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001885 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1886 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001887 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001888 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001889 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001890 if (notifyLocation != null) {
1891 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001892 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001893 if (lastLoc == null) {
1894 lastLoc = new Location(notifyLocation);
1895 r.mLastFixBroadcast = lastLoc;
1896 } else {
1897 lastLoc.set(notifyLocation);
1898 }
1899 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1900 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1901 receiverDead = true;
1902 }
Laurent Tu75defb62012-11-01 16:21:52 -07001903 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 }
1905 }
1906
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001907 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001909 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001911 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001912 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001913 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001914 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001915 }
1916 }
1917
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001918 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001919 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001920 if (deadUpdateRecords == null) {
1921 deadUpdateRecords = new ArrayList<UpdateRecord>();
1922 }
1923 deadUpdateRecords.add(r);
1924 }
1925 // track dead receivers
1926 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001927 if (deadReceivers == null) {
1928 deadReceivers = new ArrayList<Receiver>();
1929 }
1930 if (!deadReceivers.contains(receiver)) {
1931 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001932 }
1933 }
1934 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001935
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001936 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001938 for (Receiver receiver : deadReceivers) {
1939 removeUpdatesLocked(receiver);
1940 }
1941 }
1942 if (deadUpdateRecords != null) {
1943 for (UpdateRecord r : deadUpdateRecords) {
1944 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 }
Victoria Lease8b38b292012-12-04 15:04:43 -08001946 applyRequirementsLocked(provider);
1947 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001948 }
1949
1950 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001951 public LocationWorkerHandler(Looper looper) {
1952 super(looper, null, true);
1953 }
1954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 @Override
1956 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001957 switch (msg.what) {
1958 case MSG_LOCATION_CHANGED:
1959 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1960 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001961 }
1962 }
1963 }
1964
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001965 private boolean isMockProvider(String provider) {
1966 synchronized (mLock) {
1967 return mMockProviders.containsKey(provider);
1968 }
1969 }
1970
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001971 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001972 // create a working copy of the incoming Location so that the service can modify it without
1973 // disturbing the caller's copy
1974 Location myLocation = new Location(location);
1975 String provider = myLocation.getProvider();
1976
1977 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
1978 // bit if location did not come from a mock provider because passive/fused providers can
1979 // forward locations from mock providers, and should not grant them legitimacy in doing so.
1980 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
1981 myLocation.setIsFromMockProvider(true);
1982 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08001983
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001984 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001985 if (isAllowedByCurrentUserSettingsLocked(provider)) {
1986 if (!passive) {
1987 // notify passive provider of the new location
1988 mPassiveProvider.updateLocation(myLocation);
1989 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001990 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001993 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994
Mike Lockwoode97ae402010-09-29 15:23:46 -04001995 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1996 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001997 public void onPackageDisappeared(String packageName, int reason) {
1998 // remove all receivers associated with this package name
1999 synchronized (mLock) {
2000 ArrayList<Receiver> deadReceivers = null;
2001
2002 for (Receiver receiver : mReceivers.values()) {
2003 if (receiver.mPackageName.equals(packageName)) {
2004 if (deadReceivers == null) {
2005 deadReceivers = new ArrayList<Receiver>();
2006 }
2007 deadReceivers.add(receiver);
2008 }
2009 }
2010
2011 // perform removal outside of mReceivers loop
2012 if (deadReceivers != null) {
2013 for (Receiver receiver : deadReceivers) {
2014 removeUpdatesLocked(receiver);
2015 }
2016 }
2017 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002018 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002019 };
2020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 // Geocoder
2022
Nick Pellye0fd6932012-07-11 10:26:13 -07002023 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002024 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002025 return mGeocodeProvider != null;
2026 }
2027
Nick Pellye0fd6932012-07-11 10:26:13 -07002028 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002030 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002031 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002032 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2033 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002034 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002035 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 }
2037
Mike Lockwooda55c3212009-04-15 11:10:11 -04002038
Nick Pellye0fd6932012-07-11 10:26:13 -07002039 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002041 double lowerLeftLatitude, double lowerLeftLongitude,
2042 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002043 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002044
2045 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002046 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2047 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2048 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002049 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002050 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 }
2052
2053 // Mock Providers
2054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055 private void checkMockPermissionsSafe() {
2056 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2057 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2058 if (!allowMocks) {
2059 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2060 }
2061
2062 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2063 PackageManager.PERMISSION_GRANTED) {
2064 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07002065 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 }
2067
Nick Pellye0fd6932012-07-11 10:26:13 -07002068 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002069 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002070 checkMockPermissionsSafe();
2071
Mike Lockwooda4903f22010-02-17 06:42:23 -05002072 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2073 throw new IllegalArgumentException("Cannot mock the passive location provider");
2074 }
2075
Mike Lockwood86328a92009-10-23 08:38:25 -04002076 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002077 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002078 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002079 // remove the real provider if we are replacing GPS or network provider
2080 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002081 || LocationManager.NETWORK_PROVIDER.equals(name)
2082 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002083 LocationProviderInterface p = mProvidersByName.get(name);
2084 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002085 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002086 }
2087 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002088 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002089 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2090 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002091 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002092 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002093 mLastLocation.put(name, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002094 mLastLocationCoarseInterval.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002095 updateProvidersLocked();
2096 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002097 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 }
2099
Nick Pellye0fd6932012-07-11 10:26:13 -07002100 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002101 public void removeTestProvider(String provider) {
2102 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002103 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09002104 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002105 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002106 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2107 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002108 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002109 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002110
2111 // reinstate real provider if available
2112 LocationProviderInterface realProvider = mRealProviders.get(provider);
2113 if (realProvider != null) {
2114 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002115 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002116 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002117 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002118 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002119 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 }
2121 }
2122
Nick Pellye0fd6932012-07-11 10:26:13 -07002123 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002124 public void setTestProviderLocation(String provider, Location loc) {
2125 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002126 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002127 MockProvider mockProvider = mMockProviders.get(provider);
2128 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002129 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2130 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002131 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2132 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002133 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002134 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002135 }
2136 }
2137
Nick Pellye0fd6932012-07-11 10:26:13 -07002138 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002139 public void clearTestProviderLocation(String provider) {
2140 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002141 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002142 MockProvider mockProvider = mMockProviders.get(provider);
2143 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002144 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2145 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002146 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147 }
2148 }
2149
Nick Pellye0fd6932012-07-11 10:26:13 -07002150 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002151 public void setTestProviderEnabled(String provider, boolean enabled) {
2152 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002153 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002154 MockProvider mockProvider = mMockProviders.get(provider);
2155 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2157 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002158 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002159 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002160 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 mEnabledProviders.add(provider);
2162 mDisabledProviders.remove(provider);
2163 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002164 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002165 mEnabledProviders.remove(provider);
2166 mDisabledProviders.add(provider);
2167 }
2168 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002169 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 }
2171 }
2172
Nick Pellye0fd6932012-07-11 10:26:13 -07002173 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002174 public void clearTestProviderEnabled(String provider) {
2175 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002176 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002177 MockProvider mockProvider = mMockProviders.get(provider);
2178 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2180 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002181 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002182 mEnabledProviders.remove(provider);
2183 mDisabledProviders.remove(provider);
2184 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002185 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 }
2187 }
2188
Nick Pellye0fd6932012-07-11 10:26:13 -07002189 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002190 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2191 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002192 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002193 MockProvider mockProvider = mMockProviders.get(provider);
2194 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002195 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2196 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002197 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002198 }
2199 }
2200
Nick Pellye0fd6932012-07-11 10:26:13 -07002201 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 public void clearTestProviderStatus(String provider) {
2203 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002204 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002205 MockProvider mockProvider = mMockProviders.get(provider);
2206 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002207 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2208 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002209 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 }
2211 }
2212
2213 private void log(String log) {
2214 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002215 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 }
2217 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002218
2219 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002220 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2221 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2222 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002223 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224 + Binder.getCallingPid()
2225 + ", uid=" + Binder.getCallingUid());
2226 return;
2227 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002228
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002229 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002230 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002231 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002232 for (Receiver receiver : mReceivers.values()) {
2233 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002235 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002236 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2237 pw.println(" " + entry.getKey() + ":");
2238 for (UpdateRecord record : entry.getValue()) {
2239 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 }
2241 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002242 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002243 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2244 String provider = entry.getKey();
2245 Location location = entry.getValue();
2246 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002247 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002248
David Christie1b9b7b12013-04-15 15:31:11 -07002249 pw.println(" Last Known Locations Coarse Intervals:");
2250 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2251 String provider = entry.getKey();
2252 Location location = entry.getValue();
2253 pw.println(" " + provider + ": " + location);
2254 }
2255
Nick Pellye0fd6932012-07-11 10:26:13 -07002256 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 if (mEnabledProviders.size() > 0) {
2259 pw.println(" Enabled Providers:");
2260 for (String i : mEnabledProviders) {
2261 pw.println(" " + i);
2262 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002264 }
2265 if (mDisabledProviders.size() > 0) {
2266 pw.println(" Disabled Providers:");
2267 for (String i : mDisabledProviders) {
2268 pw.println(" " + i);
2269 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002270 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002271 pw.append(" ");
2272 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002273 if (mMockProviders.size() > 0) {
2274 pw.println(" Mock Providers:");
2275 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002276 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002277 }
2278 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002279
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002280 pw.append(" fudger: ");
2281 mLocationFudger.dump(fd, pw, args);
2282
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002283 if (args.length > 0 && "short".equals(args[0])) {
2284 return;
2285 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002286 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002287 pw.print(provider.getName() + " Internal State");
2288 if (provider instanceof LocationProviderProxy) {
2289 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2290 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002291 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002292 pw.println(":");
2293 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002295 }
2296 }
2297}