blob: f784030d94c6608c90066b26b2ba2794ea0e179a [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;
Victoria Lease5cd731a2012-12-19 15:04:21 -080050import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070052import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.Message;
54import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070055import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070057import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070058import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070059import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080062import android.util.Slog;
Mike Lockwoode97ae402010-09-29 15:23:46 -040063import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070064import com.android.internal.location.ProviderProperties;
65import com.android.internal.location.ProviderRequest;
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;
96 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097
Victoria Lease37425c32012-10-16 16:08:48 -070098 // Location resolution level: no location data whatsoever
99 private static final int RESOLUTION_LEVEL_NONE = 0;
100 // Location resolution level: coarse location data only
101 private static final int RESOLUTION_LEVEL_COARSE = 1;
102 // Location resolution level: fine location data
103 private static final int RESOLUTION_LEVEL_FINE = 2;
104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700106 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700108 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400109 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700110 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
111
112 private static final String NETWORK_LOCATION_SERVICE_ACTION =
113 "com.android.location.service.v2.NetworkLocationProvider";
114 private static final String FUSED_LOCATION_SERVICE_ACTION =
115 "com.android.location.service.FusedLocationProvider";
116
117 private static final int MSG_LOCATION_CHANGED = 1;
118
David Christie1b9b7b12013-04-15 15:31:11 -0700119 private static final long NANOS_PER_MILLI = 1000000L;
120
Nick Pellyf1be6862012-05-15 10:53:42 -0700121 // Location Providers may sometimes deliver location updates
122 // slightly faster that requested - provide grace period so
123 // we don't unnecessarily filter events that are otherwise on
124 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700125 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700126
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700127 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
128
129 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800130 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700131
132 // used internally for synchronization
133 private final Object mLock = new Object();
134
Victoria Lease5cd731a2012-12-19 15:04:21 -0800135 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700136 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700137 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700138 private PackageManager mPackageManager;
Victoria Leasea9770e42013-05-29 15:28:26 -0700139 private PowerManager mPowerManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700140 private GeocoderProxy mGeocodeProvider;
141 private IGpsStatusProvider mGpsStatusProvider;
142 private INetInitiatedListener mNetInitiatedListener;
143 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700144 private PassiveProvider mPassiveProvider; // track passive provider for special cases
145 private LocationBlacklist mBlacklist;
Victoria Lease5cd731a2012-12-19 15:04:21 -0800146 private HandlerThread mHandlerThread;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700147
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700148 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 // Set of providers that are explicitly enabled
150 private final Set<String> mEnabledProviders = new HashSet<String>();
151
152 // Set of providers that are explicitly disabled
153 private final Set<String> mDisabledProviders = new HashSet<String>();
154
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 // Mock (test) providers
156 private final HashMap<String, MockProvider> mMockProviders =
157 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700159 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400160 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500163 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700164 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400165
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700166 // real providers, saved here when mocked out
167 private final HashMap<String, LocationProviderInterface> mRealProviders =
168 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700170 // mapping from provider name to provider
171 private final HashMap<String, LocationProviderInterface> mProvidersByName =
172 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174 // mapping from provider name to all its UpdateRecords
175 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
176 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700177
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700178 // mapping from provider name to last known location
179 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180
David Christie1b9b7b12013-04-15 15:31:11 -0700181 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
182 // locations stored here are not fudged for coarse permissions.
183 private final HashMap<String, Location> mLastLocationCoarseInterval =
184 new HashMap<String, Location>();
185
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700186 // all providers that operate over proxy, for authorizing incoming location
187 private final ArrayList<LocationProviderProxy> mProxyProviders =
188 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189
Victoria Lease38389b62012-09-30 11:44:22 -0700190 // current active user on the device - other users are denied location data
191 private int mCurrentUserId = UserHandle.USER_OWNER;
192
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700193 public LocationManagerService(Context context) {
194 super();
195 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800196 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800197
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700198 if (D) Log.d(TAG, "Constructed");
199
200 // most startup is deferred until systemReady()
201 }
202
203 public void systemReady() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700204 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800205 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700206
Victoria Lease5cd731a2012-12-19 15:04:21 -0800207 // fetch package manager
208 mPackageManager = mContext.getPackageManager();
209
Victoria Leasea9770e42013-05-29 15:28:26 -0700210 // fetch power manager
211 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800212
213 // prepare worker thread
214 mHandlerThread = new HandlerThread(THREAD_NAME, Process.THREAD_PRIORITY_BACKGROUND);
215 mHandlerThread.start();
216 mLocationHandler = new LocationWorkerHandler(mHandlerThread.getLooper());
217
218 // prepare mLocationHandler's dependents
219 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
220 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
221 mBlacklist.init();
222 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
223
Dianne Hackbornc2293022013-02-06 23:14:49 -0800224 // Monitor for app ops mode changes.
225 AppOpsManager.Callback callback = new AppOpsManager.Callback() {
226 public void opChanged(int op, String packageName) {
227 synchronized (mLock) {
228 applyAllProviderRequirementsLocked();
229 }
230 }
231 };
232 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
233
Victoria Lease5cd731a2012-12-19 15:04:21 -0800234 // prepare providers
235 loadProvidersLocked();
236 updateProvidersLocked();
237 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700238
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700239 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700240 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700241 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700242 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800243 @Override
244 public void onChange(boolean selfChange) {
245 synchronized (mLock) {
246 updateProvidersLocked();
247 }
248 }
249 }, UserHandle.USER_ALL);
250 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700251
Victoria Lease38389b62012-09-30 11:44:22 -0700252 // listen for user change
253 IntentFilter intentFilter = new IntentFilter();
254 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
255
256 mContext.registerReceiverAsUser(new BroadcastReceiver() {
257 @Override
258 public void onReceive(Context context, Intent intent) {
259 String action = intent.getAction();
260 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
261 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
262 }
263 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800264 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700265 }
266
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500267 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
268 PackageManager pm = mContext.getPackageManager();
269 String systemPackageName = mContext.getPackageName();
270 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
271
272 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
273 new Intent(FUSED_LOCATION_SERVICE_ACTION),
274 PackageManager.GET_META_DATA, mCurrentUserId);
275 for (ResolveInfo rInfo : rInfos) {
276 String packageName = rInfo.serviceInfo.packageName;
277
278 // Check that the signature is in the list of supported sigs. If it's not in
279 // this list the standard provider binding logic won't bind to it.
280 try {
281 PackageInfo pInfo;
282 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
283 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
284 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
285 ", but has wrong signature, ignoring");
286 continue;
287 }
288 } catch (NameNotFoundException e) {
289 Log.e(TAG, "missing package: " + packageName);
290 continue;
291 }
292
293 // Get the version info
294 if (rInfo.serviceInfo.metaData == null) {
295 Log.w(TAG, "Found fused provider without metadata: " + packageName);
296 continue;
297 }
298
299 int version = rInfo.serviceInfo.metaData.getInt(
300 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
301 if (version == 0) {
302 // This should be the fallback fused location provider.
303
304 // Make sure it's in the system partition.
305 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
306 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
307 continue;
308 }
309
310 // Check that the fallback is signed the same as the OS
311 // as a proxy for coreApp="true"
312 if (pm.checkSignatures(systemPackageName, packageName)
313 != PackageManager.SIGNATURE_MATCH) {
314 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
315 + packageName);
316 continue;
317 }
318
319 // Found a valid fallback.
320 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
321 return;
322 } else {
323 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
324 }
325 }
326
327 throw new IllegalStateException("Unable to find a fused location provider that is in the "
328 + "system partition with version 0 and signed with the platform certificate. "
329 + "Such a package is needed to provide a default fused location provider in the "
330 + "event that no other fused location provider has been installed or is currently "
331 + "available. For example, coreOnly boot mode when decrypting the data "
332 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
333 }
334
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700335 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700336 // create a passive location provider, which is always enabled
337 PassiveProvider passiveProvider = new PassiveProvider(this);
338 addProviderLocked(passiveProvider);
339 mEnabledProviders.add(passiveProvider.getName());
340 mPassiveProvider = passiveProvider;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700341 // Create a gps location provider
342 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
343 mLocationHandler.getLooper());
Victoria Lease5c24fd02012-10-01 11:00:50 -0700344
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700345 if (GpsLocationProvider.isSupported()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700346 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
347 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
348 addProviderLocked(gpsProvider);
349 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
350 }
351
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700352 /*
353 Load package name(s) containing location provider support.
354 These packages can contain services implementing location providers:
355 Geocoder Provider, Network Location Provider, and
356 Fused Location Provider. They will each be searched for
357 service components implementing these providers.
358 The location framework also has support for installation
359 of new location providers at run-time. The new package does not
360 have to be explicitly listed here, however it must have a signature
361 that matches the signature of at least one package on this list.
362 */
363 Resources resources = mContext.getResources();
364 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500365 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700366 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500367 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
368 Arrays.toString(pkgs));
369 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
370
371 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700372
373 // bind to network provider
374 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
375 mContext,
376 LocationManager.NETWORK_PROVIDER,
377 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700378 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
379 com.android.internal.R.string.config_networkLocationProviderPackageName,
380 com.android.internal.R.array.config_locationProviderPackageNames,
381 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700382 if (networkProvider != null) {
383 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
384 mProxyProviders.add(networkProvider);
385 addProviderLocked(networkProvider);
386 } else {
387 Slog.w(TAG, "no network location provider found");
388 }
389
390 // bind to fused provider
391 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
392 mContext,
393 LocationManager.FUSED_PROVIDER,
394 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700395 com.android.internal.R.bool.config_enableFusedLocationOverlay,
396 com.android.internal.R.string.config_fusedLocationProviderPackageName,
397 com.android.internal.R.array.config_locationProviderPackageNames,
398 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700399 if (fusedLocationProvider != null) {
400 addProviderLocked(fusedLocationProvider);
401 mProxyProviders.add(fusedLocationProvider);
402 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700403 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700404 } else {
405 Slog.e(TAG, "no fused location provider found",
406 new IllegalStateException("Location service needs a fused location provider"));
407 }
408
409 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700410 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
411 com.android.internal.R.bool.config_enableGeocoderOverlay,
412 com.android.internal.R.string.config_geocoderProviderPackageName,
413 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800414 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700415 if (mGeocodeProvider == null) {
416 Slog.e(TAG, "no geocoder provider found");
417 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700418
419 // bind to geofence provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700420 GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
421 com.android.internal.R.bool.config_enableGeofenceOverlay,
422 com.android.internal.R.string.config_geofenceProviderPackageName,
423 com.android.internal.R.array.config_locationProviderPackageNames,
424 mLocationHandler,
425 gpsProvider.getGpsGeofenceProxy());
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700426 if (provider == null) {
427 Slog.e(TAG, "no geofence provider found");
428 }
429
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700430 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700433 * Called when the device's active user changes.
434 * @param userId the new active user's UserId
435 */
436 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700437 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800438 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700439 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700440 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700441 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700442 for (LocationProviderInterface p : mProviders) {
443 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700444 }
Victoria Lease38389b62012-09-30 11:44:22 -0700445 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700446 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700447 }
448 }
449
450 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
452 * location updates.
453 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700454 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700455 final int mUid; // uid of receiver
456 final int mPid; // pid of receiver
457 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700458 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 final ILocationListener mListener;
461 final PendingIntent mPendingIntent;
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
Mike Lockwood48f17512009-04-23 09:12:08 -0700466 int mPendingBroadcasts;
Victoria Leasea9770e42013-05-29 15:28:26 -0700467 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700469 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
470 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700473 if (listener != null) {
474 mKey = listener.asBinder();
475 } else {
476 mKey = intent;
477 }
Victoria Lease37425c32012-10-16 16:08:48 -0700478 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700479 mUid = uid;
480 mPid = pid;
481 mPackageName = packageName;
Victoria Leasea9770e42013-05-29 15:28:26 -0700482
483 // construct/configure wakelock
484 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
485 mWakeLock.setWorkSource(new WorkSource(mUid, mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 }
487
488 @Override
489 public boolean equals(Object otherObj) {
490 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700491 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 }
493 return false;
494 }
495
496 @Override
497 public int hashCode() {
498 return mKey.hashCode();
499 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 @Override
502 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700503 StringBuilder s = new StringBuilder();
504 s.append("Reciever[");
505 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700507 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700509 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700511 for (String p : mUpdateRecords.keySet()) {
512 s.append(" ").append(mUpdateRecords.get(p).toString());
513 }
514 s.append("]");
515 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 }
517
518 public boolean isListener() {
519 return mListener != null;
520 }
521
522 public boolean isPendingIntent() {
523 return mPendingIntent != null;
524 }
525
526 public ILocationListener getListener() {
527 if (mListener != null) {
528 return mListener;
529 }
530 throw new IllegalStateException("Request for non-existent listener");
531 }
532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
534 if (mListener != null) {
535 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700536 synchronized (this) {
537 // synchronize to ensure incrementPendingBroadcastsLocked()
538 // is called before decrementPendingBroadcasts()
539 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700540 // call this after broadcasting so we do not increment
541 // if we throw an exeption.
542 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 } catch (RemoteException e) {
545 return false;
546 }
547 } else {
548 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800549 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
551 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700552 synchronized (this) {
553 // synchronize to ensure incrementPendingBroadcastsLocked()
554 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700555 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700556 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700557 // call this after broadcasting so we do not increment
558 // if we throw an exeption.
559 incrementPendingBroadcastsLocked();
560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 } catch (PendingIntent.CanceledException e) {
562 return false;
563 }
564 }
565 return true;
566 }
567
568 public boolean callLocationChangedLocked(Location location) {
569 if (mListener != null) {
570 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700571 synchronized (this) {
572 // synchronize to ensure incrementPendingBroadcastsLocked()
573 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800574 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700575 // call this after broadcasting so we do not increment
576 // if we throw an exeption.
577 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 } catch (RemoteException e) {
580 return false;
581 }
582 } else {
583 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800584 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700586 synchronized (this) {
587 // synchronize to ensure incrementPendingBroadcastsLocked()
588 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700589 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700590 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700591 // call this after broadcasting so we do not increment
592 // if we throw an exeption.
593 incrementPendingBroadcastsLocked();
594 }
595 } catch (PendingIntent.CanceledException e) {
596 return false;
597 }
598 }
599 return true;
600 }
601
602 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
603 if (mListener != null) {
604 try {
605 synchronized (this) {
606 // synchronize to ensure incrementPendingBroadcastsLocked()
607 // is called before decrementPendingBroadcasts()
608 if (enabled) {
609 mListener.onProviderEnabled(provider);
610 } else {
611 mListener.onProviderDisabled(provider);
612 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700613 // call this after broadcasting so we do not increment
614 // if we throw an exeption.
615 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700616 }
617 } catch (RemoteException e) {
618 return false;
619 }
620 } else {
621 Intent providerIntent = new Intent();
622 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
623 try {
624 synchronized (this) {
625 // synchronize to ensure incrementPendingBroadcastsLocked()
626 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700627 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700628 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700629 // call this after broadcasting so we do not increment
630 // if we throw an exeption.
631 incrementPendingBroadcastsLocked();
632 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 } catch (PendingIntent.CanceledException e) {
634 return false;
635 }
636 }
637 return true;
638 }
639
Nick Pellyf1be6862012-05-15 10:53:42 -0700640 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700642 if (D) Log.d(TAG, "Location listener died");
643
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400644 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 removeUpdatesLocked(this);
646 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700647 synchronized (this) {
Victoria Leasea9770e42013-05-29 15:28:26 -0700648 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700649 }
650 }
651
Nick Pellye0fd6932012-07-11 10:26:13 -0700652 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700653 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
654 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400655 synchronized (this) {
656 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700657 }
658 }
659
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400660 // this must be called while synchronized by caller in a synchronized block
661 // containing the sending of the broadcaset
662 private void incrementPendingBroadcastsLocked() {
663 if (mPendingBroadcasts++ == 0) {
Victoria Leasea9770e42013-05-29 15:28:26 -0700664 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400665 }
666 }
667
668 private void decrementPendingBroadcastsLocked() {
669 if (--mPendingBroadcasts == 0) {
Victoria Leasea9770e42013-05-29 15:28:26 -0700670 if (mWakeLock.isHeld()) {
671 mWakeLock.release();
672 }
673 }
674 }
675
676 public void clearPendingBroadcastsLocked() {
677 if (mPendingBroadcasts > 0) {
678 mPendingBroadcasts = 0;
679 if (mWakeLock.isHeld()) {
680 mWakeLock.release();
681 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700682 }
683 }
684 }
685
Nick Pellye0fd6932012-07-11 10:26:13 -0700686 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700687 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700688 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400689 //the receiver list if it is not found. If it is not found then the
690 //LocationListener was removed when it had a pending broadcast and should
691 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700692 synchronized (mLock) {
693 IBinder binder = listener.asBinder();
694 Receiver receiver = mReceivers.get(binder);
695 if (receiver != null) {
696 synchronized (receiver) {
697 // so wakelock calls will succeed
698 long identity = Binder.clearCallingIdentity();
699 receiver.decrementPendingBroadcastsLocked();
700 Binder.restoreCallingIdentity(identity);
701 }
702 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 }
704 }
705
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700706 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400707 mProviders.add(provider);
708 mProvidersByName.put(provider.getName(), provider);
709 }
710
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700711 private void removeProviderLocked(LocationProviderInterface provider) {
712 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400713 mProviders.remove(provider);
714 mProvidersByName.remove(provider.getName());
715 }
716
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800717 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800718 * Returns "true" if access to the specified location provider is allowed by the current
719 * user's settings. Access to all location providers is forbidden to non-location-provider
720 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800721 *
722 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800723 * @return
724 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800725 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 if (mEnabledProviders.contains(provider)) {
727 return true;
728 }
729 if (mDisabledProviders.contains(provider)) {
730 return false;
731 }
732 // Use system settings
733 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734
Victoria Leaseb711d572012-10-02 13:14:11 -0700735 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 }
737
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700738 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800739 * Returns "true" if access to the specified location provider is allowed by the specified
740 * user's settings. Access to all location providers is forbidden to non-location-provider
741 * processes belonging to background users.
742 *
743 * @param provider the name of the location provider
744 * @param uid the requestor's UID
745 * @return
746 */
747 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
748 if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) {
749 return false;
750 }
751 return isAllowedByCurrentUserSettingsLocked(provider);
752 }
753
754 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700755 * Returns the permission string associated with the specified resolution level.
756 *
757 * @param resolutionLevel the resolution level
758 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700759 */
Victoria Lease37425c32012-10-16 16:08:48 -0700760 private String getResolutionPermission(int resolutionLevel) {
761 switch (resolutionLevel) {
762 case RESOLUTION_LEVEL_FINE:
763 return android.Manifest.permission.ACCESS_FINE_LOCATION;
764 case RESOLUTION_LEVEL_COARSE:
765 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
766 default:
767 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700769 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700770
Victoria Leaseda479c52012-10-15 15:24:16 -0700771 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700772 * Returns the resolution level allowed to the given PID/UID pair.
773 *
774 * @param pid the PID
775 * @param uid the UID
776 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700777 */
Victoria Lease37425c32012-10-16 16:08:48 -0700778 private int getAllowedResolutionLevel(int pid, int uid) {
779 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
780 pid, uid) == PackageManager.PERMISSION_GRANTED) {
781 return RESOLUTION_LEVEL_FINE;
782 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
783 pid, uid) == PackageManager.PERMISSION_GRANTED) {
784 return RESOLUTION_LEVEL_COARSE;
785 } else {
786 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700787 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700788 }
789
790 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700791 * Returns the resolution level allowed to the caller
792 *
793 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700794 */
Victoria Lease37425c32012-10-16 16:08:48 -0700795 private int getCallerAllowedResolutionLevel() {
796 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
797 }
798
799 /**
800 * Throw SecurityException if specified resolution level is insufficient to use geofences.
801 *
802 * @param allowedResolutionLevel resolution level allowed to caller
803 */
804 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
805 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700806 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 }
809
Victoria Lease37425c32012-10-16 16:08:48 -0700810 /**
811 * Return the minimum resolution level required to use the specified location provider.
812 *
813 * @param provider the name of the location provider
814 * @return minimum resolution level required for provider
815 */
816 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700817 if (LocationManager.GPS_PROVIDER.equals(provider) ||
818 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
819 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700820 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700821 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
822 LocationManager.FUSED_PROVIDER.equals(provider)) {
823 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700824 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700825 } else {
826 // mock providers
827 LocationProviderInterface lp = mMockProviders.get(provider);
828 if (lp != null) {
829 ProviderProperties properties = lp.getProperties();
830 if (properties != null) {
831 if (properties.mRequiresSatellite) {
832 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700833 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700834 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
835 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700836 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700837 }
838 }
839 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700840 }
Victoria Lease37425c32012-10-16 16:08:48 -0700841 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700842 }
843
Victoria Lease37425c32012-10-16 16:08:48 -0700844 /**
845 * Throw SecurityException if specified resolution level is insufficient to use the named
846 * location provider.
847 *
848 * @param allowedResolutionLevel resolution level allowed to caller
849 * @param providerName the name of the location provider
850 */
851 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
852 String providerName) {
853 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
854 if (allowedResolutionLevel < requiredResolutionLevel) {
855 switch (requiredResolutionLevel) {
856 case RESOLUTION_LEVEL_FINE:
857 throw new SecurityException("\"" + providerName + "\" location provider " +
858 "requires ACCESS_FINE_LOCATION permission.");
859 case RESOLUTION_LEVEL_COARSE:
860 throw new SecurityException("\"" + providerName + "\" location provider " +
861 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
862 default:
863 throw new SecurityException("Insufficient permission for \"" + providerName +
864 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700865 }
866 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700867 }
868
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800869 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800870 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
871 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800872 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800873 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800874 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800875 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800876 }
877 return -1;
878 }
879
880 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
881 int op = resolutionLevelToOp(allowedResolutionLevel);
882 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800883 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
884 return false;
885 }
886 }
887 return true;
888 }
889
890 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800891 int op = resolutionLevelToOp(allowedResolutionLevel);
892 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800893 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
894 return false;
895 }
896 }
897 return true;
898 }
899
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700900 /**
901 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700902 * fused, also including ones that are not permitted to
903 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700904 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700905 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700907 ArrayList<String> out;
908 synchronized (mLock) {
909 out = new ArrayList<String>(mProviders.size());
910 for (LocationProviderInterface provider : mProviders) {
911 String name = provider.getName();
912 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700913 continue;
914 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 out.add(name);
916 }
917 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700918
919 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 return out;
921 }
922
Mike Lockwood03ca2162010-04-01 08:10:09 -0700923 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700924 * Return all providers by name, that match criteria and are optionally
925 * enabled.
926 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700927 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700928 @Override
929 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700930 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700931 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800932 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -0700933 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700934 try {
935 synchronized (mLock) {
936 out = new ArrayList<String>(mProviders.size());
937 for (LocationProviderInterface provider : mProviders) {
938 String name = provider.getName();
939 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700940 continue;
941 }
Victoria Lease37425c32012-10-16 16:08:48 -0700942 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -0800943 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700944 continue;
945 }
946 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
947 name, provider.getProperties(), criteria)) {
948 continue;
949 }
950 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700951 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700952 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700953 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700954 } finally {
955 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700956 }
957
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700958 if (D) Log.d(TAG, "getProviders()=" + out);
959 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700960 }
961
962 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700963 * Return the name of the best provider given a Criteria object.
964 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700965 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700966 * has been deprecated as well. So this method now uses
967 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700968 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700969 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700970 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700971 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700972
973 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700974 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700975 result = pickBest(providers);
976 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
977 return result;
978 }
979 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700980 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700981 result = pickBest(providers);
982 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
983 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700984 }
985
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700986 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700987 return null;
988 }
989
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700990 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700991 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700992 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700993 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
994 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700995 } else {
996 return providers.get(0);
997 }
998 }
999
Nick Pellye0fd6932012-07-11 10:26:13 -07001000 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001001 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1002 LocationProviderInterface p = mProvidersByName.get(provider);
1003 if (p == null) {
1004 throw new IllegalArgumentException("provider=" + provider);
1005 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001006
1007 boolean result = LocationProvider.propertiesMeetCriteria(
1008 p.getName(), p.getProperties(), criteria);
1009 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1010 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001011 }
1012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001014 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001015 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001016 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 boolean isEnabled = p.isEnabled();
1018 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001019 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001021 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001022 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001024 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001025 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001027 }
1028 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001029 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1030 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 }
1032 }
1033
Victoria Leaseb711d572012-10-02 13:14:11 -07001034 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 int listeners = 0;
1036
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001037 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001038 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039
1040 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001041
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1043 if (records != null) {
1044 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001045 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -07001047 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001048 // Sends a notification message to the receiver
1049 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1050 if (deadReceivers == null) {
1051 deadReceivers = new ArrayList<Receiver>();
1052 }
1053 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001055 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 }
1058 }
1059
1060 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001061 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 removeUpdatesLocked(deadReceivers.get(i));
1063 }
1064 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 if (enabled) {
1067 p.enable();
1068 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001069 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 }
1071 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 }
1075
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001076 private void applyRequirementsLocked(String provider) {
1077 LocationProviderInterface p = mProvidersByName.get(provider);
1078 if (p == null) return;
1079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001081 WorkSource worksource = new WorkSource();
1082 ProviderRequest providerRequest = new ProviderRequest();
1083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001085 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001086 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001087 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1088 record.mReceiver.mAllowedResolutionLevel)) {
1089 LocationRequest locationRequest = record.mRequest;
1090 providerRequest.locationRequests.add(locationRequest);
1091 if (locationRequest.getInterval() < providerRequest.interval) {
1092 providerRequest.reportLocation = true;
1093 providerRequest.interval = locationRequest.getInterval();
1094 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001095 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001096 }
1097 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001098
1099 if (providerRequest.reportLocation) {
1100 // calculate who to blame for power
1101 // This is somewhat arbitrary. We pick a threshold interval
1102 // that is slightly higher that the minimum interval, and
1103 // spread the blame across all applications with a request
1104 // under that threshold.
1105 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1106 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001107 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001108 LocationRequest locationRequest = record.mRequest;
1109 if (locationRequest.getInterval() <= thresholdInterval) {
Dianne Hackborn002a54e2013-01-10 17:34:55 -08001110 worksource.add(record.mReceiver.mUid, record.mReceiver.mPackageName);
Victoria Leaseb711d572012-10-02 13:14:11 -07001111 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001112 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 }
1115 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001116
1117 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1118 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 }
1120
1121 private class UpdateRecord {
1122 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001123 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001125 Location mLastFixBroadcast;
1126 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127
1128 /**
1129 * Note: must be constructed with lock held.
1130 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001131 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001133 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135
1136 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1137 if (records == null) {
1138 records = new ArrayList<UpdateRecord>();
1139 mRecordsByProvider.put(provider, records);
1140 }
1141 if (!records.contains(this)) {
1142 records.add(this);
1143 }
1144 }
1145
1146 /**
1147 * Method to be called when a record will no longer be used. Calling this multiple times
1148 * must have the same effect as calling it once.
1149 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001150 void disposeLocked(boolean removeReceiver) {
1151 // remove from mRecordsByProvider
1152 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1153 if (globalRecords != null) {
1154 globalRecords.remove(this);
1155 }
1156
1157 if (!removeReceiver) return; // the caller will handle the rest
1158
1159 // remove from Receiver#mUpdateRecords
1160 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1161 if (receiverRecords != null) {
1162 receiverRecords.remove(this.mProvider);
1163
1164 // and also remove the Receiver if it has no more update records
1165 if (removeReceiver && receiverRecords.size() == 0) {
1166 removeUpdatesLocked(mReceiver);
1167 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 }
1170
1171 @Override
1172 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001173 StringBuilder s = new StringBuilder();
1174 s.append("UpdateRecord[");
1175 s.append(mProvider);
1176 s.append(' ').append(mReceiver.mPackageName).append('(');
1177 s.append(mReceiver.mUid).append(')');
1178 s.append(' ').append(mRequest);
1179 s.append(']');
1180 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 }
1183
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001184 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
1185 String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001186 IBinder binder = listener.asBinder();
1187 Receiver receiver = mReceivers.get(binder);
1188 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001189 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001190 mReceivers.put(binder, receiver);
1191
1192 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001193 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001194 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001195 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001196 return null;
1197 }
1198 }
1199 return receiver;
1200 }
1201
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001202 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001203 Receiver receiver = mReceivers.get(intent);
1204 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001205 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001206 mReceivers.put(intent, receiver);
1207 }
1208 return receiver;
1209 }
1210
Victoria Lease37425c32012-10-16 16:08:48 -07001211 /**
1212 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1213 * and consistency requirements.
1214 *
1215 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001216 * @return a version of request that meets the given resolution and consistency requirements
1217 * @hide
1218 */
1219 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1220 LocationRequest sanitizedRequest = new LocationRequest(request);
1221 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1222 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001223 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001224 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001225 break;
1226 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001227 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001228 break;
1229 }
1230 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001231 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1232 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001233 }
Victoria Lease37425c32012-10-16 16:08:48 -07001234 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1235 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001236 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001237 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001238 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001239 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001240 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001241 }
Victoria Lease37425c32012-10-16 16:08:48 -07001242 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001243 }
1244
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001245 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001246 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001247 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001248 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001249 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001250 String[] packages = mPackageManager.getPackagesForUid(uid);
1251 if (packages == null) {
1252 throw new SecurityException("invalid UID " + uid);
1253 }
1254 for (String pkg : packages) {
1255 if (packageName.equals(pkg)) return;
1256 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001257 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001258 }
1259
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001260 private void checkPendingIntent(PendingIntent intent) {
1261 if (intent == null) {
1262 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001263 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001264 }
1265
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001266 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001267 int pid, int uid, String packageName) {
1268 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001269 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001270 } else if (intent != null && listener != null) {
1271 throw new IllegalArgumentException("cannot register both listener and intent");
1272 } else if (intent != null) {
1273 checkPendingIntent(intent);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001274 return getReceiverLocked(intent, pid, uid, packageName);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001275 } else {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001276 return getReceiverLocked(listener, pid, uid, packageName);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001277 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001278 }
1279
Nick Pellye0fd6932012-07-11 10:26:13 -07001280 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001281 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1282 PendingIntent intent, String packageName) {
1283 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1284 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001285 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1286 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1287 request.getProvider());
1288 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001290 final int pid = Binder.getCallingPid();
1291 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001292 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 long identity = Binder.clearCallingIdentity();
1294 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001295 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1296 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001297 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001298
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001299 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001300 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
1301 packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001302 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001303 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 } finally {
1305 Binder.restoreCallingIdentity(identity);
1306 }
1307 }
1308
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001309 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1310 int pid, int uid, String packageName) {
1311 // Figure out the provider. Either its explicitly request (legacy use cases), or
1312 // use the fused provider
1313 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1314 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001315 if (name == null) {
1316 throw new IllegalArgumentException("provider name must not be null");
1317 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001318
1319 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1320 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001321 LocationProviderInterface provider = mProvidersByName.get(name);
1322 if (provider == null) {
1323 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1324 }
1325
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001326 UpdateRecord record = new UpdateRecord(name, request, receiver);
1327 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1328 if (oldRecord != null) {
1329 oldRecord.disposeLocked(false);
1330 }
1331
Victoria Lease09eeaec2013-02-05 11:34:13 -08001332 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001333 if (isProviderEnabled) {
1334 applyRequirementsLocked(name);
1335 } else {
1336 // Notify the listener that updates are currently disabled
1337 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001338 }
1339 }
1340
Nick Pellye0fd6932012-07-11 10:26:13 -07001341 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001342 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1343 String packageName) {
1344 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001345
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001346 final int pid = Binder.getCallingPid();
1347 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001348
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001349 synchronized (mLock) {
1350 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, packageName);
1351
1352 // providers may use public location API's, need to clear identity
1353 long identity = Binder.clearCallingIdentity();
1354 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001355 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001356 } finally {
1357 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 }
1360 }
1361
1362 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001363 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001364
1365 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1366 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1367 synchronized (receiver) {
Victoria Leasea9770e42013-05-29 15:28:26 -07001368 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001369 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001370 }
1371
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001372 // Record which providers were associated with this listener
1373 HashSet<String> providers = new HashSet<String>();
1374 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1375 if (oldRecords != null) {
1376 // Call dispose() on the obsolete update records.
1377 for (UpdateRecord record : oldRecords.values()) {
1378 record.disposeLocked(false);
1379 }
1380 // Accumulate providers
1381 providers.addAll(oldRecords.keySet());
1382 }
1383
1384 // update provider
1385 for (String provider : providers) {
1386 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001387 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001388 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 }
1390
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001391 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 }
1393 }
1394
Dianne Hackbornc2293022013-02-06 23:14:49 -08001395 private void applyAllProviderRequirementsLocked() {
1396 for (LocationProviderInterface p : mProviders) {
1397 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001398 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001399 continue;
1400 }
1401
1402 applyRequirementsLocked(p.getName());
1403 }
1404 }
1405
Nick Pellye0fd6932012-07-11 10:26:13 -07001406 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001407 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001408 if (D) Log.d(TAG, "getLastLocation: " + request);
1409 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001410 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001411 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001412 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1413 request.getProvider());
1414 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001415
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001416 final int uid = Binder.getCallingUid();
1417 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001418 try {
1419 if (mBlacklist.isBlacklisted(packageName)) {
1420 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1421 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001422 return null;
1423 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001424
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001425 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1426 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1427 packageName);
1428 return null;
1429 }
1430
Victoria Leaseb711d572012-10-02 13:14:11 -07001431 synchronized (mLock) {
1432 // Figure out the provider. Either its explicitly request (deprecated API's),
1433 // or use the fused provider
1434 String name = request.getProvider();
1435 if (name == null) name = LocationManager.FUSED_PROVIDER;
1436 LocationProviderInterface provider = mProvidersByName.get(name);
1437 if (provider == null) return null;
1438
Victoria Lease09eeaec2013-02-05 11:34:13 -08001439 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001440
David Christie1b9b7b12013-04-15 15:31:11 -07001441 Location location;
1442 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1443 // Make sure that an app with coarse permissions can't get frequent location
1444 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1445 location = mLastLocationCoarseInterval.get(name);
1446 } else {
1447 location = mLastLocation.get(name);
1448 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001449 if (location == null) {
1450 return null;
1451 }
Victoria Lease37425c32012-10-16 16:08:48 -07001452 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001453 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1454 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001455 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001456 }
Victoria Lease37425c32012-10-16 16:08:48 -07001457 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001458 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001459 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001460 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001461 return null;
1462 } finally {
1463 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001464 }
1465 }
1466
1467 @Override
1468 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1469 String packageName) {
1470 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001471 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1472 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001473 checkPendingIntent(intent);
1474 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001475 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1476 request.getProvider());
1477 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001478
Victoria Lease37425c32012-10-16 16:08:48 -07001479 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001480
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001481 // geo-fence manager uses the public location API, need to clear identity
1482 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001483 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1484 // temporary measure until geofences work for secondary users
1485 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1486 return;
1487 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001488 long identity = Binder.clearCallingIdentity();
1489 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001490 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1491 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001492 } finally {
1493 Binder.restoreCallingIdentity(identity);
1494 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001495 }
1496
1497 @Override
1498 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001499 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001500 checkPendingIntent(intent);
1501 checkPackageName(packageName);
1502
1503 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1504
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001505 // geo-fence manager uses the public location API, need to clear identity
1506 long identity = Binder.clearCallingIdentity();
1507 try {
1508 mGeofenceManager.removeFence(geofence, intent);
1509 } finally {
1510 Binder.restoreCallingIdentity(identity);
1511 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001512 }
1513
1514
1515 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001516 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001517 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 return false;
1519 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001520 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1521 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001522 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001524 final int uid = Binder.getCallingUid();
1525 final long ident = Binder.clearCallingIdentity();
1526 try {
Victoria Lease3d5173d2013-02-05 16:07:32 -08001527 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001528 return false;
1529 }
1530 } finally {
1531 Binder.restoreCallingIdentity(ident);
1532 }
1533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001535 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001537 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 return false;
1539 }
1540 return true;
1541 }
1542
Nick Pellye0fd6932012-07-11 10:26:13 -07001543 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001545 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001546 try {
1547 mGpsStatusProvider.removeGpsStatusListener(listener);
1548 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001549 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001550 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 }
1552 }
1553
Nick Pellye0fd6932012-07-11 10:26:13 -07001554 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001556 if (provider == null) {
1557 // throw NullPointerException to remain compatible with previous implementation
1558 throw new NullPointerException();
1559 }
Victoria Lease37425c32012-10-16 16:08:48 -07001560 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1561 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001564 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 != PackageManager.PERMISSION_GRANTED)) {
1566 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1567 }
1568
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001569 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001570 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001571 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001572
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001573 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 }
1575 }
1576
Nick Pellye0fd6932012-07-11 10:26:13 -07001577 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001578 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001579 if (Binder.getCallingUid() != Process.myUid()) {
1580 throw new SecurityException(
1581 "calling sendNiResponse from outside of the system is not allowed");
1582 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001583 try {
1584 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001585 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001586 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001587 return false;
1588 }
1589 }
1590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001592 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001593 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 * accessed by the caller
1595 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001596 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001597 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001598 if (mProvidersByName.get(provider) == null) {
1599 return null;
1600 }
1601
Victoria Lease37425c32012-10-16 16:08:48 -07001602 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1603 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001605 LocationProviderInterface p;
1606 synchronized (mLock) {
1607 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 }
1609
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001610 if (p == null) return null;
1611 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 }
1613
Nick Pellye0fd6932012-07-11 10:26:13 -07001614 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001616 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1617 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001618 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1619
Victoria Lease09eeaec2013-02-05 11:34:13 -08001620 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001621 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001622 try {
1623 synchronized (mLock) {
1624 LocationProviderInterface p = mProvidersByName.get(provider);
1625 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001626
Victoria Lease09eeaec2013-02-05 11:34:13 -08001627 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001628 }
1629 } finally {
1630 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001631 }
1632 }
1633
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001634 /**
1635 * Returns "true" if the UID belongs to a bound location provider.
1636 *
1637 * @param uid the uid
1638 * @return true if uid belongs to a bound location provider
1639 */
1640 private boolean isUidALocationProvider(int uid) {
1641 if (uid == Process.SYSTEM_UID) {
1642 return true;
1643 }
1644 if (mGeocodeProvider != null) {
1645 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1646 }
1647 for (LocationProviderProxy proxy : mProxyProviders) {
1648 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
1649 }
1650 return false;
1651 }
1652
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001653 private void checkCallerIsProvider() {
1654 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1655 == PackageManager.PERMISSION_GRANTED) {
1656 return;
1657 }
1658
1659 // Previously we only used the INSTALL_LOCATION_PROVIDER
1660 // check. But that is system or signature
1661 // protection level which is not flexible enough for
1662 // providers installed oustide the system image. So
1663 // also allow providers with a UID matching the
1664 // currently bound package name
1665
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001666 if (isUidALocationProvider(Binder.getCallingUid())) {
1667 return;
1668 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001669
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001670 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1671 "or UID of a currently bound location provider");
1672 }
1673
1674 private boolean doesPackageHaveUid(int uid, String packageName) {
1675 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 return false;
1677 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001678 try {
1679 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1680 if (appInfo.uid != uid) {
1681 return false;
1682 }
1683 } catch (NameNotFoundException e) {
1684 return false;
1685 }
1686 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 }
1688
Nick Pellye0fd6932012-07-11 10:26:13 -07001689 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001690 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001691 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001692
Nick Pelly2eeeec22012-07-18 13:13:37 -07001693 if (!location.isComplete()) {
1694 Log.w(TAG, "Dropping incomplete location: " + location);
1695 return;
1696 }
1697
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001698 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1699 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001700 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001701 mLocationHandler.sendMessageAtFrontOfQueue(m);
1702 }
1703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704
Laurent Tu75defb62012-11-01 16:21:52 -07001705 private static boolean shouldBroadcastSafe(
1706 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 // Always broadcast the first update
1708 if (lastLoc == null) {
1709 return true;
1710 }
1711
Nick Pellyf1be6862012-05-15 10:53:42 -07001712 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001713 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07001714 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
1715 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001716 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 return false;
1718 }
1719
1720 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001721 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 if (minDistance > 0.0) {
1723 if (loc.distanceTo(lastLoc) <= minDistance) {
1724 return false;
1725 }
1726 }
1727
Laurent Tu75defb62012-11-01 16:21:52 -07001728 // Check whether sufficient number of udpates is left
1729 if (record.mRequest.getNumUpdates() <= 0) {
1730 return false;
1731 }
1732
1733 // Check whether the expiry date has passed
1734 if (record.mRequest.getExpireAt() < now) {
1735 return false;
1736 }
1737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 return true;
1739 }
1740
Mike Lockwooda4903f22010-02-17 06:42:23 -05001741 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001742 if (D) Log.d(TAG, "incoming location: " + location);
1743
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001744 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001745 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746
Laurent Tu60ec50a2012-10-04 17:00:10 -07001747 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001748 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001749 if (p == null) return;
1750
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001751 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001752 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1753 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001754 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001755 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001756 lastLocation = new Location(provider);
1757 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001758 } else {
1759 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1760 if (noGPSLocation == null && lastNoGPSLocation != null) {
1761 // New location has no no-GPS location: adopt last no-GPS location. This is set
1762 // directly into location because we do not want to notify COARSE clients.
1763 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1764 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001765 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001766 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767
David Christie1b9b7b12013-04-15 15:31:11 -07001768 // Update last known coarse interval location if enough time has passed.
1769 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
1770 if (lastLocationCoarseInterval == null) {
1771 lastLocationCoarseInterval = new Location(location);
1772 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
1773 }
1774 long timeDiffNanos = location.getElapsedRealtimeNanos()
1775 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
1776 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
1777 lastLocationCoarseInterval.set(location);
1778 }
1779 // Don't ever return a coarse location that is more recent than the allowed update
1780 // interval (i.e. don't allow an app to keep registering and unregistering for
1781 // location updates to overcome the minimum interval).
1782 noGPSLocation =
1783 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1784
Laurent Tu60ec50a2012-10-04 17:00:10 -07001785 // Skip if there are no UpdateRecords for this provider.
1786 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1787 if (records == null || records.size() == 0) return;
1788
Victoria Lease09016ab2012-09-16 12:33:15 -07001789 // Fetch coarse location
1790 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07001791 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001792 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1793 }
1794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 // Fetch latest status update time
1796 long newStatusUpdateTime = p.getStatusUpdateTime();
1797
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001798 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 Bundle extras = new Bundle();
1800 int status = p.getStatus(extras);
1801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001803 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001806 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001808 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001809
Victoria Lease269518e2012-10-29 08:25:39 -07001810 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Victoria Leased9ba79e2013-05-07 14:22:02 -07001811 if (receiverUserId != mCurrentUserId && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001812 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001813 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001814 " (current user: " + mCurrentUserId + ", app: " +
1815 receiver.mPackageName + ")");
1816 }
1817 continue;
1818 }
1819
Nick Pelly4035f5a2012-08-17 14:43:49 -07001820 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1821 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1822 receiver.mPackageName);
1823 continue;
1824 }
1825
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001826 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
1827 receiver.mAllowedResolutionLevel)) {
1828 if (D) Log.d(TAG, "skipping loc update for no op app: " +
1829 receiver.mPackageName);
1830 continue;
1831 }
1832
Victoria Lease09016ab2012-09-16 12:33:15 -07001833 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001834 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1835 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001836 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001837 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001838 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001839 if (notifyLocation != null) {
1840 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001841 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001842 if (lastLoc == null) {
1843 lastLoc = new Location(notifyLocation);
1844 r.mLastFixBroadcast = lastLoc;
1845 } else {
1846 lastLoc.set(notifyLocation);
1847 }
1848 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1849 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1850 receiverDead = true;
1851 }
Laurent Tu75defb62012-11-01 16:21:52 -07001852 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 }
1854 }
1855
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001856 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001858 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001860 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001862 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001863 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001864 }
1865 }
1866
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001867 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001868 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001869 if (deadUpdateRecords == null) {
1870 deadUpdateRecords = new ArrayList<UpdateRecord>();
1871 }
1872 deadUpdateRecords.add(r);
1873 }
1874 // track dead receivers
1875 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001876 if (deadReceivers == null) {
1877 deadReceivers = new ArrayList<Receiver>();
1878 }
1879 if (!deadReceivers.contains(receiver)) {
1880 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 }
1882 }
1883 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001884
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001885 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001887 for (Receiver receiver : deadReceivers) {
1888 removeUpdatesLocked(receiver);
1889 }
1890 }
1891 if (deadUpdateRecords != null) {
1892 for (UpdateRecord r : deadUpdateRecords) {
1893 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 }
Victoria Lease8b38b292012-12-04 15:04:43 -08001895 applyRequirementsLocked(provider);
1896 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 }
1898
1899 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001900 public LocationWorkerHandler(Looper looper) {
1901 super(looper, null, true);
1902 }
1903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 @Override
1905 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001906 switch (msg.what) {
1907 case MSG_LOCATION_CHANGED:
1908 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1909 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 }
1911 }
1912 }
1913
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001914 private boolean isMockProvider(String provider) {
1915 synchronized (mLock) {
1916 return mMockProviders.containsKey(provider);
1917 }
1918 }
1919
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001920 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001921 // create a working copy of the incoming Location so that the service can modify it without
1922 // disturbing the caller's copy
1923 Location myLocation = new Location(location);
1924 String provider = myLocation.getProvider();
1925
1926 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
1927 // bit if location did not come from a mock provider because passive/fused providers can
1928 // forward locations from mock providers, and should not grant them legitimacy in doing so.
1929 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
1930 myLocation.setIsFromMockProvider(true);
1931 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08001932
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001933 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001934 if (isAllowedByCurrentUserSettingsLocked(provider)) {
1935 if (!passive) {
1936 // notify passive provider of the new location
1937 mPassiveProvider.updateLocation(myLocation);
1938 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001939 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001942 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943
Mike Lockwoode97ae402010-09-29 15:23:46 -04001944 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1945 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001946 public void onPackageDisappeared(String packageName, int reason) {
1947 // remove all receivers associated with this package name
1948 synchronized (mLock) {
1949 ArrayList<Receiver> deadReceivers = null;
1950
1951 for (Receiver receiver : mReceivers.values()) {
1952 if (receiver.mPackageName.equals(packageName)) {
1953 if (deadReceivers == null) {
1954 deadReceivers = new ArrayList<Receiver>();
1955 }
1956 deadReceivers.add(receiver);
1957 }
1958 }
1959
1960 // perform removal outside of mReceivers loop
1961 if (deadReceivers != null) {
1962 for (Receiver receiver : deadReceivers) {
1963 removeUpdatesLocked(receiver);
1964 }
1965 }
1966 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001967 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001968 };
1969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 // Geocoder
1971
Nick Pellye0fd6932012-07-11 10:26:13 -07001972 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001973 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001974 return mGeocodeProvider != null;
1975 }
1976
Nick Pellye0fd6932012-07-11 10:26:13 -07001977 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001979 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001980 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001981 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1982 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001984 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985 }
1986
Mike Lockwooda55c3212009-04-15 11:10:11 -04001987
Nick Pellye0fd6932012-07-11 10:26:13 -07001988 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001990 double lowerLeftLatitude, double lowerLeftLongitude,
1991 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001992 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001993
1994 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001995 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1996 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1997 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001999 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
2001
2002 // Mock Providers
2003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 private void checkMockPermissionsSafe() {
2005 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2006 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2007 if (!allowMocks) {
2008 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2009 }
2010
2011 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2012 PackageManager.PERMISSION_GRANTED) {
2013 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07002014 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 }
2016
Nick Pellye0fd6932012-07-11 10:26:13 -07002017 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002018 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 checkMockPermissionsSafe();
2020
Mike Lockwooda4903f22010-02-17 06:42:23 -05002021 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2022 throw new IllegalArgumentException("Cannot mock the passive location provider");
2023 }
2024
Mike Lockwood86328a92009-10-23 08:38:25 -04002025 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002026 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002027 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002028 // remove the real provider if we are replacing GPS or network provider
2029 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002030 || LocationManager.NETWORK_PROVIDER.equals(name)
2031 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002032 LocationProviderInterface p = mProvidersByName.get(name);
2033 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002034 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002035 }
2036 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002037 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002038 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2039 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002040 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002041 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002042 mLastLocation.put(name, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002043 mLastLocationCoarseInterval.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 updateProvidersLocked();
2045 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002046 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002047 }
2048
Nick Pellye0fd6932012-07-11 10:26:13 -07002049 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 public void removeTestProvider(String provider) {
2051 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002052 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09002053 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002054 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2056 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002057 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002058 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002059
2060 // reinstate real provider if available
2061 LocationProviderInterface realProvider = mRealProviders.get(provider);
2062 if (realProvider != null) {
2063 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002064 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002065 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002066 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002068 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 }
2070 }
2071
Nick Pellye0fd6932012-07-11 10:26:13 -07002072 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 public void setTestProviderLocation(String provider, Location loc) {
2074 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002075 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002076 MockProvider mockProvider = mMockProviders.get(provider);
2077 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2079 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002080 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2081 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002082 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002083 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002084 }
2085 }
2086
Nick Pellye0fd6932012-07-11 10:26:13 -07002087 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002088 public void clearTestProviderLocation(String provider) {
2089 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002090 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002091 MockProvider mockProvider = mMockProviders.get(provider);
2092 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002093 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2094 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002095 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002096 }
2097 }
2098
Nick Pellye0fd6932012-07-11 10:26:13 -07002099 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002100 public void setTestProviderEnabled(String provider, boolean enabled) {
2101 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002102 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002103 MockProvider mockProvider = mMockProviders.get(provider);
2104 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002105 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2106 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002107 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002109 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 mEnabledProviders.add(provider);
2111 mDisabledProviders.remove(provider);
2112 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002113 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002114 mEnabledProviders.remove(provider);
2115 mDisabledProviders.add(provider);
2116 }
2117 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002118 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 }
2120 }
2121
Nick Pellye0fd6932012-07-11 10:26:13 -07002122 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002123 public void clearTestProviderEnabled(String provider) {
2124 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002125 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002126 MockProvider mockProvider = mMockProviders.get(provider);
2127 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002128 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2129 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002130 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002131 mEnabledProviders.remove(provider);
2132 mDisabledProviders.remove(provider);
2133 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -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 setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
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.setStatus(status, extras, updateTime);
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 clearTestProviderStatus(String provider) {
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 Lockwood7ec434e2009-03-27 07:46:48 -07002158 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002159 }
2160 }
2161
2162 private void log(String log) {
2163 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002164 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002165 }
2166 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002167
2168 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002169 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2170 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2171 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002172 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002173 + Binder.getCallingPid()
2174 + ", uid=" + Binder.getCallingUid());
2175 return;
2176 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002177
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002178 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002180 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002181 for (Receiver receiver : mReceivers.values()) {
2182 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002185 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2186 pw.println(" " + entry.getKey() + ":");
2187 for (UpdateRecord record : entry.getValue()) {
2188 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002189 }
2190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002191 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002192 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2193 String provider = entry.getKey();
2194 Location location = entry.getValue();
2195 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002197
David Christie1b9b7b12013-04-15 15:31:11 -07002198 pw.println(" Last Known Locations Coarse Intervals:");
2199 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2200 String provider = entry.getKey();
2201 Location location = entry.getValue();
2202 pw.println(" " + provider + ": " + location);
2203 }
2204
Nick Pellye0fd6932012-07-11 10:26:13 -07002205 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002207 if (mEnabledProviders.size() > 0) {
2208 pw.println(" Enabled Providers:");
2209 for (String i : mEnabledProviders) {
2210 pw.println(" " + i);
2211 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 }
2214 if (mDisabledProviders.size() > 0) {
2215 pw.println(" Disabled Providers:");
2216 for (String i : mDisabledProviders) {
2217 pw.println(" " + i);
2218 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002220 pw.append(" ");
2221 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 if (mMockProviders.size() > 0) {
2223 pw.println(" Mock Providers:");
2224 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002225 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002226 }
2227 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002228
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002229 pw.append(" fudger: ");
2230 mLocationFudger.dump(fd, pw, args);
2231
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002232 if (args.length > 0 && "short".equals(args[0])) {
2233 return;
2234 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002235 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002236 pw.print(provider.getName() + " Internal State");
2237 if (provider instanceof LocationProviderProxy) {
2238 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2239 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002240 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002241 pw.println(":");
2242 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002244 }
2245 }
2246}