blob: b47e8a041efcc5501ca65b6b5ae8d4d4f9867f7e [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;
138 private PowerManager.WakeLock mWakeLock;
139 private PackageManager mPackageManager;
140 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
148 // --- fields below are protected by mWakeLock ---
149 private int mPendingBroadcasts;
150
151 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 // Set of providers that are explicitly enabled
153 private final Set<String> mEnabledProviders = new HashSet<String>();
154
155 // Set of providers that are explicitly disabled
156 private final Set<String> mDisabledProviders = new HashSet<String>();
157
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700158 // Mock (test) providers
159 private final HashMap<String, MockProvider> mMockProviders =
160 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400163 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700165 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500166 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // real providers, saved here when mocked out
170 private final HashMap<String, LocationProviderInterface> mRealProviders =
171 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700173 // mapping from provider name to provider
174 private final HashMap<String, LocationProviderInterface> mProvidersByName =
175 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 // mapping from provider name to all its UpdateRecords
178 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
179 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700180
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 // mapping from provider name to last known location
182 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
David Christie1b9b7b12013-04-15 15:31:11 -0700184 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
185 // locations stored here are not fudged for coarse permissions.
186 private final HashMap<String, Location> mLastLocationCoarseInterval =
187 new HashMap<String, Location>();
188
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700189 // all providers that operate over proxy, for authorizing incoming location
190 private final ArrayList<LocationProviderProxy> mProxyProviders =
191 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192
Victoria Lease38389b62012-09-30 11:44:22 -0700193 // current active user on the device - other users are denied location data
194 private int mCurrentUserId = UserHandle.USER_OWNER;
195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 public LocationManagerService(Context context) {
197 super();
198 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800199 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800200
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700201 if (D) Log.d(TAG, "Constructed");
202
203 // most startup is deferred until systemReady()
204 }
205
206 public void systemReady() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700207 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800208 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700209
Victoria Lease5cd731a2012-12-19 15:04:21 -0800210 // fetch package manager
211 mPackageManager = mContext.getPackageManager();
212
213 // prepare wake lock
214 PowerManager powerManager =
215 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
216 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
217
218 // prepare worker thread
219 mHandlerThread = new HandlerThread(THREAD_NAME, Process.THREAD_PRIORITY_BACKGROUND);
220 mHandlerThread.start();
221 mLocationHandler = new LocationWorkerHandler(mHandlerThread.getLooper());
222
223 // prepare mLocationHandler's dependents
224 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
225 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
226 mBlacklist.init();
227 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
228
Dianne Hackbornc2293022013-02-06 23:14:49 -0800229 // Monitor for app ops mode changes.
230 AppOpsManager.Callback callback = new AppOpsManager.Callback() {
231 public void opChanged(int op, String packageName) {
232 synchronized (mLock) {
233 applyAllProviderRequirementsLocked();
234 }
235 }
236 };
237 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
238
Victoria Lease5cd731a2012-12-19 15:04:21 -0800239 // prepare providers
240 loadProvidersLocked();
241 updateProvidersLocked();
242 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700243
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700244 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700245 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700246 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700247 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800248 @Override
249 public void onChange(boolean selfChange) {
250 synchronized (mLock) {
251 updateProvidersLocked();
252 }
253 }
254 }, UserHandle.USER_ALL);
255 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700256
Victoria Lease38389b62012-09-30 11:44:22 -0700257 // listen for user change
258 IntentFilter intentFilter = new IntentFilter();
259 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
260
261 mContext.registerReceiverAsUser(new BroadcastReceiver() {
262 @Override
263 public void onReceive(Context context, Intent intent) {
264 String action = intent.getAction();
265 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
266 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
267 }
268 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800269 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700270 }
271
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500272 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
273 PackageManager pm = mContext.getPackageManager();
274 String systemPackageName = mContext.getPackageName();
275 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
276
277 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
278 new Intent(FUSED_LOCATION_SERVICE_ACTION),
279 PackageManager.GET_META_DATA, mCurrentUserId);
280 for (ResolveInfo rInfo : rInfos) {
281 String packageName = rInfo.serviceInfo.packageName;
282
283 // Check that the signature is in the list of supported sigs. If it's not in
284 // this list the standard provider binding logic won't bind to it.
285 try {
286 PackageInfo pInfo;
287 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
288 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
289 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
290 ", but has wrong signature, ignoring");
291 continue;
292 }
293 } catch (NameNotFoundException e) {
294 Log.e(TAG, "missing package: " + packageName);
295 continue;
296 }
297
298 // Get the version info
299 if (rInfo.serviceInfo.metaData == null) {
300 Log.w(TAG, "Found fused provider without metadata: " + packageName);
301 continue;
302 }
303
304 int version = rInfo.serviceInfo.metaData.getInt(
305 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
306 if (version == 0) {
307 // This should be the fallback fused location provider.
308
309 // Make sure it's in the system partition.
310 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
311 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
312 continue;
313 }
314
315 // Check that the fallback is signed the same as the OS
316 // as a proxy for coreApp="true"
317 if (pm.checkSignatures(systemPackageName, packageName)
318 != PackageManager.SIGNATURE_MATCH) {
319 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
320 + packageName);
321 continue;
322 }
323
324 // Found a valid fallback.
325 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
326 return;
327 } else {
328 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
329 }
330 }
331
332 throw new IllegalStateException("Unable to find a fused location provider that is in the "
333 + "system partition with version 0 and signed with the platform certificate. "
334 + "Such a package is needed to provide a default fused location provider in the "
335 + "event that no other fused location provider has been installed or is currently "
336 + "available. For example, coreOnly boot mode when decrypting the data "
337 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
338 }
339
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700340 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700341 // create a passive location provider, which is always enabled
342 PassiveProvider passiveProvider = new PassiveProvider(this);
343 addProviderLocked(passiveProvider);
344 mEnabledProviders.add(passiveProvider.getName());
345 mPassiveProvider = passiveProvider;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700346 // Create a gps location provider
347 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
348 mLocationHandler.getLooper());
Victoria Lease5c24fd02012-10-01 11:00:50 -0700349
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700350 if (GpsLocationProvider.isSupported()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700351 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
352 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
353 addProviderLocked(gpsProvider);
354 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
355 }
356
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700357 /*
358 Load package name(s) containing location provider support.
359 These packages can contain services implementing location providers:
360 Geocoder Provider, Network Location Provider, and
361 Fused Location Provider. They will each be searched for
362 service components implementing these providers.
363 The location framework also has support for installation
364 of new location providers at run-time. The new package does not
365 have to be explicitly listed here, however it must have a signature
366 that matches the signature of at least one package on this list.
367 */
368 Resources resources = mContext.getResources();
369 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500370 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700371 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500372 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
373 Arrays.toString(pkgs));
374 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
375
376 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700377
378 // bind to network provider
379 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
380 mContext,
381 LocationManager.NETWORK_PROVIDER,
382 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800383 providerPackageNames, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700384 if (networkProvider != null) {
385 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
386 mProxyProviders.add(networkProvider);
387 addProviderLocked(networkProvider);
388 } else {
389 Slog.w(TAG, "no network location provider found");
390 }
391
392 // bind to fused provider
393 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
394 mContext,
395 LocationManager.FUSED_PROVIDER,
396 FUSED_LOCATION_SERVICE_ACTION,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800397 providerPackageNames, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700398 if (fusedLocationProvider != null) {
399 addProviderLocked(fusedLocationProvider);
400 mProxyProviders.add(fusedLocationProvider);
401 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700402 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700403 } else {
404 Slog.e(TAG, "no fused location provider found",
405 new IllegalStateException("Location service needs a fused location provider"));
406 }
407
408 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700409 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800410 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700411 if (mGeocodeProvider == null) {
412 Slog.e(TAG, "no geocoder provider found");
413 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700414
415 // bind to geofence provider
416 GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, providerPackageNames,
417 mLocationHandler, gpsProvider.getGpsGeofenceProxy());
418 if (provider == null) {
419 Slog.e(TAG, "no geofence provider found");
420 }
421
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700422 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700425 * Called when the device's active user changes.
426 * @param userId the new active user's UserId
427 */
428 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700429 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800430 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700431 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700432 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700433 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700434 for (LocationProviderInterface p : mProviders) {
435 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700436 }
Victoria Lease38389b62012-09-30 11:44:22 -0700437 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700438 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700439 }
440 }
441
442 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
444 * location updates.
445 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700446 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700447 final int mUid; // uid of receiver
448 final int mPid; // pid of receiver
449 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700450 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 final ILocationListener mListener;
453 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700455
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400456 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700457
Mike Lockwood48f17512009-04-23 09:12:08 -0700458 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700460 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
461 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700464 if (listener != null) {
465 mKey = listener.asBinder();
466 } else {
467 mKey = intent;
468 }
Victoria Lease37425c32012-10-16 16:08:48 -0700469 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700470 mUid = uid;
471 mPid = pid;
472 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 }
474
475 @Override
476 public boolean equals(Object otherObj) {
477 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700478 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 }
480 return false;
481 }
482
483 @Override
484 public int hashCode() {
485 return mKey.hashCode();
486 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 @Override
489 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700490 StringBuilder s = new StringBuilder();
491 s.append("Reciever[");
492 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700494 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700496 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700498 for (String p : mUpdateRecords.keySet()) {
499 s.append(" ").append(mUpdateRecords.get(p).toString());
500 }
501 s.append("]");
502 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 }
504
505 public boolean isListener() {
506 return mListener != null;
507 }
508
509 public boolean isPendingIntent() {
510 return mPendingIntent != null;
511 }
512
513 public ILocationListener getListener() {
514 if (mListener != null) {
515 return mListener;
516 }
517 throw new IllegalStateException("Request for non-existent listener");
518 }
519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
521 if (mListener != null) {
522 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700523 synchronized (this) {
524 // synchronize to ensure incrementPendingBroadcastsLocked()
525 // is called before decrementPendingBroadcasts()
526 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700527 // call this after broadcasting so we do not increment
528 // if we throw an exeption.
529 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700530 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 } catch (RemoteException e) {
532 return false;
533 }
534 } else {
535 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800536 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
538 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700539 synchronized (this) {
540 // synchronize to ensure incrementPendingBroadcastsLocked()
541 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700542 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700543 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700544 // call this after broadcasting so we do not increment
545 // if we throw an exeption.
546 incrementPendingBroadcastsLocked();
547 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 } catch (PendingIntent.CanceledException e) {
549 return false;
550 }
551 }
552 return true;
553 }
554
555 public boolean callLocationChangedLocked(Location location) {
556 if (mListener != null) {
557 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700558 synchronized (this) {
559 // synchronize to ensure incrementPendingBroadcastsLocked()
560 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800561 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700562 // call this after broadcasting so we do not increment
563 // if we throw an exeption.
564 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 } catch (RemoteException e) {
567 return false;
568 }
569 } else {
570 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800571 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700573 synchronized (this) {
574 // synchronize to ensure incrementPendingBroadcastsLocked()
575 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700576 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700577 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700578 // call this after broadcasting so we do not increment
579 // if we throw an exeption.
580 incrementPendingBroadcastsLocked();
581 }
582 } catch (PendingIntent.CanceledException e) {
583 return false;
584 }
585 }
586 return true;
587 }
588
589 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
590 if (mListener != null) {
591 try {
592 synchronized (this) {
593 // synchronize to ensure incrementPendingBroadcastsLocked()
594 // is called before decrementPendingBroadcasts()
595 if (enabled) {
596 mListener.onProviderEnabled(provider);
597 } else {
598 mListener.onProviderDisabled(provider);
599 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700600 // call this after broadcasting so we do not increment
601 // if we throw an exeption.
602 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700603 }
604 } catch (RemoteException e) {
605 return false;
606 }
607 } else {
608 Intent providerIntent = new Intent();
609 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
610 try {
611 synchronized (this) {
612 // synchronize to ensure incrementPendingBroadcastsLocked()
613 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700614 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700615 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700616 // call this after broadcasting so we do not increment
617 // if we throw an exeption.
618 incrementPendingBroadcastsLocked();
619 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 } catch (PendingIntent.CanceledException e) {
621 return false;
622 }
623 }
624 return true;
625 }
626
Nick Pellyf1be6862012-05-15 10:53:42 -0700627 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700629 if (D) Log.d(TAG, "Location listener died");
630
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400631 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 removeUpdatesLocked(this);
633 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700634 synchronized (this) {
635 if (mPendingBroadcasts > 0) {
636 LocationManagerService.this.decrementPendingBroadcasts();
637 mPendingBroadcasts = 0;
638 }
639 }
640 }
641
Nick Pellye0fd6932012-07-11 10:26:13 -0700642 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700643 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
644 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400645 synchronized (this) {
646 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700647 }
648 }
649
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400650 // this must be called while synchronized by caller in a synchronized block
651 // containing the sending of the broadcaset
652 private void incrementPendingBroadcastsLocked() {
653 if (mPendingBroadcasts++ == 0) {
654 LocationManagerService.this.incrementPendingBroadcasts();
655 }
656 }
657
658 private void decrementPendingBroadcastsLocked() {
659 if (--mPendingBroadcasts == 0) {
660 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700661 }
662 }
663 }
664
Nick Pellye0fd6932012-07-11 10:26:13 -0700665 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700666 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400667 //Do not use getReceiver here as that will add the ILocationListener to
668 //the receiver list if it is not found. If it is not found then the
669 //LocationListener was removed when it had a pending broadcast and should
670 //not be added back.
671 IBinder binder = listener.asBinder();
672 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700673 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400674 synchronized (receiver) {
675 // so wakelock calls will succeed
676 long identity = Binder.clearCallingIdentity();
677 receiver.decrementPendingBroadcastsLocked();
678 Binder.restoreCallingIdentity(identity);
679 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 }
681 }
682
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700683 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400684 mProviders.add(provider);
685 mProvidersByName.put(provider.getName(), provider);
686 }
687
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700688 private void removeProviderLocked(LocationProviderInterface provider) {
689 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400690 mProviders.remove(provider);
691 mProvidersByName.remove(provider.getName());
692 }
693
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800694 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800695 * Returns "true" if access to the specified location provider is allowed by the current
696 * user's settings. Access to all location providers is forbidden to non-location-provider
697 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800698 *
699 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800700 * @return
701 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800702 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 if (mEnabledProviders.contains(provider)) {
704 return true;
705 }
706 if (mDisabledProviders.contains(provider)) {
707 return false;
708 }
709 // Use system settings
710 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711
Victoria Leaseb711d572012-10-02 13:14:11 -0700712 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 }
714
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700715 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800716 * Returns "true" if access to the specified location provider is allowed by the specified
717 * user's settings. Access to all location providers is forbidden to non-location-provider
718 * processes belonging to background users.
719 *
720 * @param provider the name of the location provider
721 * @param uid the requestor's UID
722 * @return
723 */
724 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
725 if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) {
726 return false;
727 }
728 return isAllowedByCurrentUserSettingsLocked(provider);
729 }
730
731 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700732 * Returns the permission string associated with the specified resolution level.
733 *
734 * @param resolutionLevel the resolution level
735 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700736 */
Victoria Lease37425c32012-10-16 16:08:48 -0700737 private String getResolutionPermission(int resolutionLevel) {
738 switch (resolutionLevel) {
739 case RESOLUTION_LEVEL_FINE:
740 return android.Manifest.permission.ACCESS_FINE_LOCATION;
741 case RESOLUTION_LEVEL_COARSE:
742 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
743 default:
744 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700746 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700747
Victoria Leaseda479c52012-10-15 15:24:16 -0700748 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700749 * Returns the resolution level allowed to the given PID/UID pair.
750 *
751 * @param pid the PID
752 * @param uid the UID
753 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700754 */
Victoria Lease37425c32012-10-16 16:08:48 -0700755 private int getAllowedResolutionLevel(int pid, int uid) {
756 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
757 pid, uid) == PackageManager.PERMISSION_GRANTED) {
758 return RESOLUTION_LEVEL_FINE;
759 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
760 pid, uid) == PackageManager.PERMISSION_GRANTED) {
761 return RESOLUTION_LEVEL_COARSE;
762 } else {
763 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700764 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700765 }
766
767 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700768 * Returns the resolution level allowed to the caller
769 *
770 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700771 */
Victoria Lease37425c32012-10-16 16:08:48 -0700772 private int getCallerAllowedResolutionLevel() {
773 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
774 }
775
776 /**
777 * Throw SecurityException if specified resolution level is insufficient to use geofences.
778 *
779 * @param allowedResolutionLevel resolution level allowed to caller
780 */
781 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
782 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700783 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
784 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 }
786
Victoria Lease37425c32012-10-16 16:08:48 -0700787 /**
788 * Return the minimum resolution level required to use the specified location provider.
789 *
790 * @param provider the name of the location provider
791 * @return minimum resolution level required for provider
792 */
793 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700794 if (LocationManager.GPS_PROVIDER.equals(provider) ||
795 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
796 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700797 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700798 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
799 LocationManager.FUSED_PROVIDER.equals(provider)) {
800 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700801 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700802 } else {
803 // mock providers
804 LocationProviderInterface lp = mMockProviders.get(provider);
805 if (lp != null) {
806 ProviderProperties properties = lp.getProperties();
807 if (properties != null) {
808 if (properties.mRequiresSatellite) {
809 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700810 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700811 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
812 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700813 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700814 }
815 }
816 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700817 }
Victoria Lease37425c32012-10-16 16:08:48 -0700818 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700819 }
820
Victoria Lease37425c32012-10-16 16:08:48 -0700821 /**
822 * Throw SecurityException if specified resolution level is insufficient to use the named
823 * location provider.
824 *
825 * @param allowedResolutionLevel resolution level allowed to caller
826 * @param providerName the name of the location provider
827 */
828 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
829 String providerName) {
830 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
831 if (allowedResolutionLevel < requiredResolutionLevel) {
832 switch (requiredResolutionLevel) {
833 case RESOLUTION_LEVEL_FINE:
834 throw new SecurityException("\"" + providerName + "\" location provider " +
835 "requires ACCESS_FINE_LOCATION permission.");
836 case RESOLUTION_LEVEL_COARSE:
837 throw new SecurityException("\"" + providerName + "\" location provider " +
838 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
839 default:
840 throw new SecurityException("Insufficient permission for \"" + providerName +
841 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700842 }
843 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700844 }
845
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800846 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800847 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
848 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800849 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800850 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800851 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800852 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800853 }
854 return -1;
855 }
856
857 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
858 int op = resolutionLevelToOp(allowedResolutionLevel);
859 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800860 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
861 return false;
862 }
863 }
864 return true;
865 }
866
867 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800868 int op = resolutionLevelToOp(allowedResolutionLevel);
869 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800870 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
871 return false;
872 }
873 }
874 return true;
875 }
876
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700877 /**
878 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700879 * fused, also including ones that are not permitted to
880 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700881 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700882 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700884 ArrayList<String> out;
885 synchronized (mLock) {
886 out = new ArrayList<String>(mProviders.size());
887 for (LocationProviderInterface provider : mProviders) {
888 String name = provider.getName();
889 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700890 continue;
891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 out.add(name);
893 }
894 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700895
896 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 return out;
898 }
899
Mike Lockwood03ca2162010-04-01 08:10:09 -0700900 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700901 * Return all providers by name, that match criteria and are optionally
902 * enabled.
903 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700904 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700905 @Override
906 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700907 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700908 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800909 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -0700910 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700911 try {
912 synchronized (mLock) {
913 out = new ArrayList<String>(mProviders.size());
914 for (LocationProviderInterface provider : mProviders) {
915 String name = provider.getName();
916 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700917 continue;
918 }
Victoria Lease37425c32012-10-16 16:08:48 -0700919 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -0800920 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700921 continue;
922 }
923 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
924 name, provider.getProperties(), criteria)) {
925 continue;
926 }
927 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700928 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700929 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700930 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700931 } finally {
932 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700933 }
934
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700935 if (D) Log.d(TAG, "getProviders()=" + out);
936 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700937 }
938
939 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700940 * Return the name of the best provider given a Criteria object.
941 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700942 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700943 * has been deprecated as well. So this method now uses
944 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700945 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700946 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700947 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700948 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700949
950 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700951 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700952 result = pickBest(providers);
953 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
954 return result;
955 }
956 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700957 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700958 result = pickBest(providers);
959 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
960 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700961 }
962
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700963 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700964 return null;
965 }
966
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700967 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700968 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700969 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700970 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
971 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700972 } else {
973 return providers.get(0);
974 }
975 }
976
Nick Pellye0fd6932012-07-11 10:26:13 -0700977 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700978 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
979 LocationProviderInterface p = mProvidersByName.get(provider);
980 if (p == null) {
981 throw new IllegalArgumentException("provider=" + provider);
982 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700983
984 boolean result = LocationProvider.propertiesMeetCriteria(
985 p.getName(), p.getProperties(), criteria);
986 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
987 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700988 }
989
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700991 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400992 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500993 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 boolean isEnabled = p.isEnabled();
995 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -0800996 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700998 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700999 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001001 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001002 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001004 }
1005 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001006 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1007 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 }
1009 }
1010
Victoria Leaseb711d572012-10-02 13:14:11 -07001011 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 int listeners = 0;
1013
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001014 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001015 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016
1017 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1020 if (records != null) {
1021 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001022 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -07001024 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001025 // Sends a notification message to the receiver
1026 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1027 if (deadReceivers == null) {
1028 deadReceivers = new ArrayList<Receiver>();
1029 }
1030 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001032 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 }
1035 }
1036
1037 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001038 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 removeUpdatesLocked(deadReceivers.get(i));
1040 }
1041 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 if (enabled) {
1044 p.enable();
1045 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001046 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 }
1048 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 }
1052
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001053 private void applyRequirementsLocked(String provider) {
1054 LocationProviderInterface p = mProvidersByName.get(provider);
1055 if (p == null) return;
1056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001058 WorkSource worksource = new WorkSource();
1059 ProviderRequest providerRequest = new ProviderRequest();
1060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001062 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001063 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001064 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1065 record.mReceiver.mAllowedResolutionLevel)) {
1066 LocationRequest locationRequest = record.mRequest;
1067 providerRequest.locationRequests.add(locationRequest);
1068 if (locationRequest.getInterval() < providerRequest.interval) {
1069 providerRequest.reportLocation = true;
1070 providerRequest.interval = locationRequest.getInterval();
1071 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001072 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001073 }
1074 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001075
1076 if (providerRequest.reportLocation) {
1077 // calculate who to blame for power
1078 // This is somewhat arbitrary. We pick a threshold interval
1079 // that is slightly higher that the minimum interval, and
1080 // spread the blame across all applications with a request
1081 // under that threshold.
1082 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1083 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001084 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001085 LocationRequest locationRequest = record.mRequest;
1086 if (locationRequest.getInterval() <= thresholdInterval) {
Dianne Hackborn002a54e2013-01-10 17:34:55 -08001087 worksource.add(record.mReceiver.mUid, record.mReceiver.mPackageName);
Victoria Leaseb711d572012-10-02 13:14:11 -07001088 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001089 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 }
1092 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001093
1094 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1095 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 }
1097
1098 private class UpdateRecord {
1099 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001100 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001102 Location mLastFixBroadcast;
1103 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104
1105 /**
1106 * Note: must be constructed with lock held.
1107 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001108 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001110 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112
1113 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1114 if (records == null) {
1115 records = new ArrayList<UpdateRecord>();
1116 mRecordsByProvider.put(provider, records);
1117 }
1118 if (!records.contains(this)) {
1119 records.add(this);
1120 }
1121 }
1122
1123 /**
1124 * Method to be called when a record will no longer be used. Calling this multiple times
1125 * must have the same effect as calling it once.
1126 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001127 void disposeLocked(boolean removeReceiver) {
1128 // remove from mRecordsByProvider
1129 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1130 if (globalRecords != null) {
1131 globalRecords.remove(this);
1132 }
1133
1134 if (!removeReceiver) return; // the caller will handle the rest
1135
1136 // remove from Receiver#mUpdateRecords
1137 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1138 if (receiverRecords != null) {
1139 receiverRecords.remove(this.mProvider);
1140
1141 // and also remove the Receiver if it has no more update records
1142 if (removeReceiver && receiverRecords.size() == 0) {
1143 removeUpdatesLocked(mReceiver);
1144 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001145 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 }
1147
1148 @Override
1149 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001150 StringBuilder s = new StringBuilder();
1151 s.append("UpdateRecord[");
1152 s.append(mProvider);
1153 s.append(' ').append(mReceiver.mPackageName).append('(');
1154 s.append(mReceiver.mUid).append(')');
1155 s.append(' ').append(mRequest);
1156 s.append(']');
1157 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 }
1160
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001161 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001162 IBinder binder = listener.asBinder();
1163 Receiver receiver = mReceivers.get(binder);
1164 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001165 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001166 mReceivers.put(binder, receiver);
1167
1168 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001169 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001170 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001171 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001172 return null;
1173 }
1174 }
1175 return receiver;
1176 }
1177
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001178 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001179 Receiver receiver = mReceivers.get(intent);
1180 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001181 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001182 mReceivers.put(intent, receiver);
1183 }
1184 return receiver;
1185 }
1186
Victoria Lease37425c32012-10-16 16:08:48 -07001187 /**
1188 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1189 * and consistency requirements.
1190 *
1191 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001192 * @return a version of request that meets the given resolution and consistency requirements
1193 * @hide
1194 */
1195 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1196 LocationRequest sanitizedRequest = new LocationRequest(request);
1197 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1198 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001199 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001200 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001201 break;
1202 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001203 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001204 break;
1205 }
1206 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001207 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1208 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001209 }
Victoria Lease37425c32012-10-16 16:08:48 -07001210 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1211 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001212 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001213 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001214 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001215 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001216 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001217 }
Victoria Lease37425c32012-10-16 16:08:48 -07001218 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001219 }
1220
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001221 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001222 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001223 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001224 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001225 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001226 String[] packages = mPackageManager.getPackagesForUid(uid);
1227 if (packages == null) {
1228 throw new SecurityException("invalid UID " + uid);
1229 }
1230 for (String pkg : packages) {
1231 if (packageName.equals(pkg)) return;
1232 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001233 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001234 }
1235
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236 private void checkPendingIntent(PendingIntent intent) {
1237 if (intent == null) {
1238 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001239 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001240 }
1241
1242 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1243 int pid, int uid, String packageName) {
1244 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001245 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001246 } else if (intent != null && listener != null) {
1247 throw new IllegalArgumentException("cannot register both listener and intent");
1248 } else if (intent != null) {
1249 checkPendingIntent(intent);
1250 return getReceiver(intent, pid, uid, packageName);
1251 } else {
1252 return getReceiver(listener, pid, uid, packageName);
1253 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001254 }
1255
Nick Pellye0fd6932012-07-11 10:26:13 -07001256 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001257 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1258 PendingIntent intent, String packageName) {
1259 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1260 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001261 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1262 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1263 request.getProvider());
1264 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001266 final int pid = Binder.getCallingPid();
1267 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001268 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 long identity = Binder.clearCallingIdentity();
1270 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001271 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1272 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001273 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001274 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1275
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001276 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001277 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001278 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 } finally {
1280 Binder.restoreCallingIdentity(identity);
1281 }
1282 }
1283
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1285 int pid, int uid, String packageName) {
1286 // Figure out the provider. Either its explicitly request (legacy use cases), or
1287 // use the fused provider
1288 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1289 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001290 if (name == null) {
1291 throw new IllegalArgumentException("provider name must not be null");
1292 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001293 LocationProviderInterface provider = mProvidersByName.get(name);
1294 if (provider == null) {
1295 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1296 }
1297
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001298 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1299 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001300
1301 UpdateRecord record = new UpdateRecord(name, request, receiver);
1302 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1303 if (oldRecord != null) {
1304 oldRecord.disposeLocked(false);
1305 }
1306
Victoria Lease09eeaec2013-02-05 11:34:13 -08001307 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001308 if (isProviderEnabled) {
1309 applyRequirementsLocked(name);
1310 } else {
1311 // Notify the listener that updates are currently disabled
1312 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 }
1314 }
1315
Nick Pellye0fd6932012-07-11 10:26:13 -07001316 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001317 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1318 String packageName) {
1319 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001320
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001321 final int pid = Binder.getCallingPid();
1322 final int uid = Binder.getCallingUid();
1323 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1324
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001325 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001326 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001328 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001329 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001331 } finally {
1332 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 }
1334 }
1335
1336 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001337 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001338
1339 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1340 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1341 synchronized (receiver) {
1342 if (receiver.mPendingBroadcasts > 0) {
1343 decrementPendingBroadcasts();
1344 receiver.mPendingBroadcasts = 0;
1345 }
1346 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 }
1348
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001349 // Record which providers were associated with this listener
1350 HashSet<String> providers = new HashSet<String>();
1351 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1352 if (oldRecords != null) {
1353 // Call dispose() on the obsolete update records.
1354 for (UpdateRecord record : oldRecords.values()) {
1355 record.disposeLocked(false);
1356 }
1357 // Accumulate providers
1358 providers.addAll(oldRecords.keySet());
1359 }
1360
1361 // update provider
1362 for (String provider : providers) {
1363 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001364 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001365 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 }
1367
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001368 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 }
1370 }
1371
Dianne Hackbornc2293022013-02-06 23:14:49 -08001372 private void applyAllProviderRequirementsLocked() {
1373 for (LocationProviderInterface p : mProviders) {
1374 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001375 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001376 continue;
1377 }
1378
1379 applyRequirementsLocked(p.getName());
1380 }
1381 }
1382
Nick Pellye0fd6932012-07-11 10:26:13 -07001383 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001384 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001385 if (D) Log.d(TAG, "getLastLocation: " + request);
1386 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001387 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001388 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001389 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1390 request.getProvider());
1391 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001392
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001393 final int uid = Binder.getCallingUid();
1394 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001395 try {
1396 if (mBlacklist.isBlacklisted(packageName)) {
1397 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1398 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001399 return null;
1400 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001401
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001402 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1403 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1404 packageName);
1405 return null;
1406 }
1407
Victoria Leaseb711d572012-10-02 13:14:11 -07001408 synchronized (mLock) {
1409 // Figure out the provider. Either its explicitly request (deprecated API's),
1410 // or use the fused provider
1411 String name = request.getProvider();
1412 if (name == null) name = LocationManager.FUSED_PROVIDER;
1413 LocationProviderInterface provider = mProvidersByName.get(name);
1414 if (provider == null) return null;
1415
Victoria Lease09eeaec2013-02-05 11:34:13 -08001416 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001417
David Christie1b9b7b12013-04-15 15:31:11 -07001418 Location location;
1419 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1420 // Make sure that an app with coarse permissions can't get frequent location
1421 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1422 location = mLastLocationCoarseInterval.get(name);
1423 } else {
1424 location = mLastLocation.get(name);
1425 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001426 if (location == null) {
1427 return null;
1428 }
Victoria Lease37425c32012-10-16 16:08:48 -07001429 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001430 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1431 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001432 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001433 }
Victoria Lease37425c32012-10-16 16:08:48 -07001434 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001435 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001436 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001437 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001438 return null;
1439 } finally {
1440 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001441 }
1442 }
1443
1444 @Override
1445 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1446 String packageName) {
1447 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001448 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1449 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001450 checkPendingIntent(intent);
1451 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001452 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1453 request.getProvider());
1454 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001455
Victoria Lease37425c32012-10-16 16:08:48 -07001456 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001457
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001458 // geo-fence manager uses the public location API, need to clear identity
1459 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001460 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1461 // temporary measure until geofences work for secondary users
1462 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1463 return;
1464 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001465 long identity = Binder.clearCallingIdentity();
1466 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001467 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1468 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001469 } finally {
1470 Binder.restoreCallingIdentity(identity);
1471 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001472 }
1473
1474 @Override
1475 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001476 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001477 checkPendingIntent(intent);
1478 checkPackageName(packageName);
1479
1480 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1481
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001482 // geo-fence manager uses the public location API, need to clear identity
1483 long identity = Binder.clearCallingIdentity();
1484 try {
1485 mGeofenceManager.removeFence(geofence, intent);
1486 } finally {
1487 Binder.restoreCallingIdentity(identity);
1488 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001489 }
1490
1491
1492 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001493 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001494 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 return false;
1496 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001497 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1498 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001499 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001501 final int uid = Binder.getCallingUid();
1502 final long ident = Binder.clearCallingIdentity();
1503 try {
Victoria Lease3d5173d2013-02-05 16:07:32 -08001504 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001505 return false;
1506 }
1507 } finally {
1508 Binder.restoreCallingIdentity(ident);
1509 }
1510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001512 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001514 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 return false;
1516 }
1517 return true;
1518 }
1519
Nick Pellye0fd6932012-07-11 10:26:13 -07001520 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001522 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001523 try {
1524 mGpsStatusProvider.removeGpsStatusListener(listener);
1525 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001526 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001527 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 }
1529 }
1530
Nick Pellye0fd6932012-07-11 10:26:13 -07001531 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001532 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001533 if (provider == null) {
1534 // throw NullPointerException to remain compatible with previous implementation
1535 throw new NullPointerException();
1536 }
Victoria Lease37425c32012-10-16 16:08:48 -07001537 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1538 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001540 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001541 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 != PackageManager.PERMISSION_GRANTED)) {
1543 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1544 }
1545
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001546 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001547 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001548 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001549
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001550 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 }
1552 }
1553
Nick Pellye0fd6932012-07-11 10:26:13 -07001554 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001555 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001556 if (Binder.getCallingUid() != Process.myUid()) {
1557 throw new SecurityException(
1558 "calling sendNiResponse from outside of the system is not allowed");
1559 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001560 try {
1561 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001562 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001563 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001564 return false;
1565 }
1566 }
1567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001569 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001570 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 * accessed by the caller
1572 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001573 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001574 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001575 if (mProvidersByName.get(provider) == null) {
1576 return null;
1577 }
1578
Victoria Lease37425c32012-10-16 16:08:48 -07001579 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1580 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001582 LocationProviderInterface p;
1583 synchronized (mLock) {
1584 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 }
1586
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001587 if (p == null) return null;
1588 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001589 }
1590
Nick Pellye0fd6932012-07-11 10:26:13 -07001591 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001593 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1594 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001595 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1596
Victoria Lease09eeaec2013-02-05 11:34:13 -08001597 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001598 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001599 try {
1600 synchronized (mLock) {
1601 LocationProviderInterface p = mProvidersByName.get(provider);
1602 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001603
Victoria Lease09eeaec2013-02-05 11:34:13 -08001604 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001605 }
1606 } finally {
1607 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001608 }
1609 }
1610
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001611 /**
1612 * Returns "true" if the UID belongs to a bound location provider.
1613 *
1614 * @param uid the uid
1615 * @return true if uid belongs to a bound location provider
1616 */
1617 private boolean isUidALocationProvider(int uid) {
1618 if (uid == Process.SYSTEM_UID) {
1619 return true;
1620 }
1621 if (mGeocodeProvider != null) {
1622 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1623 }
1624 for (LocationProviderProxy proxy : mProxyProviders) {
1625 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
1626 }
1627 return false;
1628 }
1629
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001630 private void checkCallerIsProvider() {
1631 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1632 == PackageManager.PERMISSION_GRANTED) {
1633 return;
1634 }
1635
1636 // Previously we only used the INSTALL_LOCATION_PROVIDER
1637 // check. But that is system or signature
1638 // protection level which is not flexible enough for
1639 // providers installed oustide the system image. So
1640 // also allow providers with a UID matching the
1641 // currently bound package name
1642
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001643 if (isUidALocationProvider(Binder.getCallingUid())) {
1644 return;
1645 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001646
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001647 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1648 "or UID of a currently bound location provider");
1649 }
1650
1651 private boolean doesPackageHaveUid(int uid, String packageName) {
1652 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 return false;
1654 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001655 try {
1656 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1657 if (appInfo.uid != uid) {
1658 return false;
1659 }
1660 } catch (NameNotFoundException e) {
1661 return false;
1662 }
1663 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 }
1665
Nick Pellye0fd6932012-07-11 10:26:13 -07001666 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001667 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001668 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001669
Nick Pelly2eeeec22012-07-18 13:13:37 -07001670 if (!location.isComplete()) {
1671 Log.w(TAG, "Dropping incomplete location: " + location);
1672 return;
1673 }
1674
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001675 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1676 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001677 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001678 mLocationHandler.sendMessageAtFrontOfQueue(m);
1679 }
1680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681
Laurent Tu75defb62012-11-01 16:21:52 -07001682 private static boolean shouldBroadcastSafe(
1683 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 // Always broadcast the first update
1685 if (lastLoc == null) {
1686 return true;
1687 }
1688
Nick Pellyf1be6862012-05-15 10:53:42 -07001689 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001690 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07001691 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
1692 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001693 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 return false;
1695 }
1696
1697 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001698 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 if (minDistance > 0.0) {
1700 if (loc.distanceTo(lastLoc) <= minDistance) {
1701 return false;
1702 }
1703 }
1704
Laurent Tu75defb62012-11-01 16:21:52 -07001705 // Check whether sufficient number of udpates is left
1706 if (record.mRequest.getNumUpdates() <= 0) {
1707 return false;
1708 }
1709
1710 // Check whether the expiry date has passed
1711 if (record.mRequest.getExpireAt() < now) {
1712 return false;
1713 }
1714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 return true;
1716 }
1717
Mike Lockwooda4903f22010-02-17 06:42:23 -05001718 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001719 if (D) Log.d(TAG, "incoming location: " + location);
1720
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001721 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001722 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723
Laurent Tu60ec50a2012-10-04 17:00:10 -07001724 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001725 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001726 if (p == null) return;
1727
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001728 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001729 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1730 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001731 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001732 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001733 lastLocation = new Location(provider);
1734 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001735 } else {
1736 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1737 if (noGPSLocation == null && lastNoGPSLocation != null) {
1738 // New location has no no-GPS location: adopt last no-GPS location. This is set
1739 // directly into location because we do not want to notify COARSE clients.
1740 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1741 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001742 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001743 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744
David Christie1b9b7b12013-04-15 15:31:11 -07001745 // Update last known coarse interval location if enough time has passed.
1746 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
1747 if (lastLocationCoarseInterval == null) {
1748 lastLocationCoarseInterval = new Location(location);
1749 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
1750 }
1751 long timeDiffNanos = location.getElapsedRealtimeNanos()
1752 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
1753 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
1754 lastLocationCoarseInterval.set(location);
1755 }
1756 // Don't ever return a coarse location that is more recent than the allowed update
1757 // interval (i.e. don't allow an app to keep registering and unregistering for
1758 // location updates to overcome the minimum interval).
1759 noGPSLocation =
1760 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1761
Laurent Tu60ec50a2012-10-04 17:00:10 -07001762 // Skip if there are no UpdateRecords for this provider.
1763 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1764 if (records == null || records.size() == 0) return;
1765
Victoria Lease09016ab2012-09-16 12:33:15 -07001766 // Fetch coarse location
1767 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07001768 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001769 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1770 }
1771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 // Fetch latest status update time
1773 long newStatusUpdateTime = p.getStatusUpdateTime();
1774
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001775 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776 Bundle extras = new Bundle();
1777 int status = p.getStatus(extras);
1778
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001780 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001783 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001785 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001786
Victoria Lease269518e2012-10-29 08:25:39 -07001787 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1788 if (receiverUserId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001789 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001790 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001791 " (current user: " + mCurrentUserId + ", app: " +
1792 receiver.mPackageName + ")");
1793 }
1794 continue;
1795 }
1796
Nick Pelly4035f5a2012-08-17 14:43:49 -07001797 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1798 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1799 receiver.mPackageName);
1800 continue;
1801 }
1802
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001803 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
1804 receiver.mAllowedResolutionLevel)) {
1805 if (D) Log.d(TAG, "skipping loc update for no op app: " +
1806 receiver.mPackageName);
1807 continue;
1808 }
1809
Victoria Lease09016ab2012-09-16 12:33:15 -07001810 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001811 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1812 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001813 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001814 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001815 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001816 if (notifyLocation != null) {
1817 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001818 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001819 if (lastLoc == null) {
1820 lastLoc = new Location(notifyLocation);
1821 r.mLastFixBroadcast = lastLoc;
1822 } else {
1823 lastLoc.set(notifyLocation);
1824 }
1825 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1826 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1827 receiverDead = true;
1828 }
Laurent Tu75defb62012-11-01 16:21:52 -07001829 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 }
1831 }
1832
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001833 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001835 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001837 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001839 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001840 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001841 }
1842 }
1843
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001844 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001845 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001846 if (deadUpdateRecords == null) {
1847 deadUpdateRecords = new ArrayList<UpdateRecord>();
1848 }
1849 deadUpdateRecords.add(r);
1850 }
1851 // track dead receivers
1852 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001853 if (deadReceivers == null) {
1854 deadReceivers = new ArrayList<Receiver>();
1855 }
1856 if (!deadReceivers.contains(receiver)) {
1857 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858 }
1859 }
1860 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001861
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001862 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001864 for (Receiver receiver : deadReceivers) {
1865 removeUpdatesLocked(receiver);
1866 }
1867 }
1868 if (deadUpdateRecords != null) {
1869 for (UpdateRecord r : deadUpdateRecords) {
1870 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 }
Victoria Lease8b38b292012-12-04 15:04:43 -08001872 applyRequirementsLocked(provider);
1873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 }
1875
1876 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001877 public LocationWorkerHandler(Looper looper) {
1878 super(looper, null, true);
1879 }
1880
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 @Override
1882 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001883 switch (msg.what) {
1884 case MSG_LOCATION_CHANGED:
1885 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1886 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 }
1888 }
1889 }
1890
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001891 private boolean isMockProvider(String provider) {
1892 synchronized (mLock) {
1893 return mMockProviders.containsKey(provider);
1894 }
1895 }
1896
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001897 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001898 // create a working copy of the incoming Location so that the service can modify it without
1899 // disturbing the caller's copy
1900 Location myLocation = new Location(location);
1901 String provider = myLocation.getProvider();
1902
1903 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
1904 // bit if location did not come from a mock provider because passive/fused providers can
1905 // forward locations from mock providers, and should not grant them legitimacy in doing so.
1906 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
1907 myLocation.setIsFromMockProvider(true);
1908 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08001909
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001910 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001911 if (isAllowedByCurrentUserSettingsLocked(provider)) {
1912 if (!passive) {
1913 // notify passive provider of the new location
1914 mPassiveProvider.updateLocation(myLocation);
1915 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001916 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001919 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920
Mike Lockwoode97ae402010-09-29 15:23:46 -04001921 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1922 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001923 public void onPackageDisappeared(String packageName, int reason) {
1924 // remove all receivers associated with this package name
1925 synchronized (mLock) {
1926 ArrayList<Receiver> deadReceivers = null;
1927
1928 for (Receiver receiver : mReceivers.values()) {
1929 if (receiver.mPackageName.equals(packageName)) {
1930 if (deadReceivers == null) {
1931 deadReceivers = new ArrayList<Receiver>();
1932 }
1933 deadReceivers.add(receiver);
1934 }
1935 }
1936
1937 // perform removal outside of mReceivers loop
1938 if (deadReceivers != null) {
1939 for (Receiver receiver : deadReceivers) {
1940 removeUpdatesLocked(receiver);
1941 }
1942 }
1943 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001944 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001945 };
1946
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 // Wake locks
1948
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001949 private void incrementPendingBroadcasts() {
1950 synchronized (mWakeLock) {
1951 if (mPendingBroadcasts++ == 0) {
1952 try {
1953 mWakeLock.acquire();
1954 log("Acquired wakelock");
1955 } catch (Exception e) {
1956 // This is to catch a runtime exception thrown when we try to release an
1957 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001958 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001959 }
1960 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001961 }
1962 }
1963
1964 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001965 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001966 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001967 try {
1968 // Release wake lock
1969 if (mWakeLock.isHeld()) {
1970 mWakeLock.release();
1971 log("Released wakelock");
1972 } else {
1973 log("Can't release wakelock again!");
1974 }
1975 } catch (Exception e) {
1976 // This is to catch a runtime exception thrown when we try to release an
1977 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001978 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001979 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001980 }
1981 }
1982 }
1983
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 // Geocoder
1985
Nick Pellye0fd6932012-07-11 10:26:13 -07001986 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001987 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001988 return mGeocodeProvider != null;
1989 }
1990
Nick Pellye0fd6932012-07-11 10:26:13 -07001991 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001993 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001994 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001995 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1996 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001998 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 }
2000
Mike Lockwooda55c3212009-04-15 11:10:11 -04002001
Nick Pellye0fd6932012-07-11 10:26:13 -07002002 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002003 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002004 double lowerLeftLatitude, double lowerLeftLongitude,
2005 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002006 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002007
2008 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002009 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2010 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2011 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002013 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002014 }
2015
2016 // Mock Providers
2017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 private void checkMockPermissionsSafe() {
2019 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2020 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2021 if (!allowMocks) {
2022 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2023 }
2024
2025 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2026 PackageManager.PERMISSION_GRANTED) {
2027 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07002028 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 }
2030
Nick Pellye0fd6932012-07-11 10:26:13 -07002031 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002032 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002033 checkMockPermissionsSafe();
2034
Mike Lockwooda4903f22010-02-17 06:42:23 -05002035 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2036 throw new IllegalArgumentException("Cannot mock the passive location provider");
2037 }
2038
Mike Lockwood86328a92009-10-23 08:38:25 -04002039 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002040 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002041 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002042 // remove the real provider if we are replacing GPS or network provider
2043 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002044 || LocationManager.NETWORK_PROVIDER.equals(name)
2045 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002046 LocationProviderInterface p = mProvidersByName.get(name);
2047 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002048 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002049 }
2050 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002051 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2053 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002054 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002055 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002056 mLastLocation.put(name, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002057 mLastLocationCoarseInterval.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 updateProvidersLocked();
2059 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002060 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 }
2062
Nick Pellye0fd6932012-07-11 10:26:13 -07002063 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002064 public void removeTestProvider(String provider) {
2065 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002066 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09002067 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002068 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2070 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002071 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002072 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002073
2074 // reinstate real provider if available
2075 LocationProviderInterface realProvider = mRealProviders.get(provider);
2076 if (realProvider != null) {
2077 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002078 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002079 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002080 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002081 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002082 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 }
2084 }
2085
Nick Pellye0fd6932012-07-11 10:26:13 -07002086 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 public void setTestProviderLocation(String provider, Location loc) {
2088 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002089 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002090 MockProvider mockProvider = mMockProviders.get(provider);
2091 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002092 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2093 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002094 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2095 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002096 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002097 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 }
2099 }
2100
Nick Pellye0fd6932012-07-11 10:26:13 -07002101 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002102 public void clearTestProviderLocation(String provider) {
2103 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002104 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002105 MockProvider mockProvider = mMockProviders.get(provider);
2106 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2108 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002109 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 }
2111 }
2112
Nick Pellye0fd6932012-07-11 10:26:13 -07002113 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002114 public void setTestProviderEnabled(String provider, boolean enabled) {
2115 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002116 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002117 MockProvider mockProvider = mMockProviders.get(provider);
2118 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2120 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002121 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002122 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002123 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002124 mEnabledProviders.add(provider);
2125 mDisabledProviders.remove(provider);
2126 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002127 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002128 mEnabledProviders.remove(provider);
2129 mDisabledProviders.add(provider);
2130 }
2131 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002132 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002133 }
2134 }
2135
Nick Pellye0fd6932012-07-11 10:26:13 -07002136 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 public void clearTestProviderEnabled(String provider) {
2138 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002139 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002140 MockProvider mockProvider = mMockProviders.get(provider);
2141 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002142 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2143 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002144 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145 mEnabledProviders.remove(provider);
2146 mDisabledProviders.remove(provider);
2147 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002148 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002149 }
2150 }
2151
Nick Pellye0fd6932012-07-11 10:26:13 -07002152 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002153 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2154 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002155 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002156 MockProvider mockProvider = mMockProviders.get(provider);
2157 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002158 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2159 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002160 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 }
2162 }
2163
Nick Pellye0fd6932012-07-11 10:26:13 -07002164 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002165 public void clearTestProviderStatus(String provider) {
2166 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002167 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002168 MockProvider mockProvider = mMockProviders.get(provider);
2169 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2171 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002172 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002173 }
2174 }
2175
2176 private void log(String log) {
2177 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002178 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 }
2180 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002181
2182 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2184 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2185 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002186 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002187 + Binder.getCallingPid()
2188 + ", uid=" + Binder.getCallingUid());
2189 return;
2190 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002191
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002192 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002193 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002195 for (Receiver receiver : mReceivers.values()) {
2196 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002198 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002199 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2200 pw.println(" " + entry.getKey() + ":");
2201 for (UpdateRecord record : entry.getValue()) {
2202 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 }
2204 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002205 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002206 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2207 String provider = entry.getKey();
2208 Location location = entry.getValue();
2209 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002211
David Christie1b9b7b12013-04-15 15:31:11 -07002212 pw.println(" Last Known Locations Coarse Intervals:");
2213 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2214 String provider = entry.getKey();
2215 Location location = entry.getValue();
2216 pw.println(" " + provider + ": " + location);
2217 }
2218
Nick Pellye0fd6932012-07-11 10:26:13 -07002219 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002221 if (mEnabledProviders.size() > 0) {
2222 pw.println(" Enabled Providers:");
2223 for (String i : mEnabledProviders) {
2224 pw.println(" " + i);
2225 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 }
2228 if (mDisabledProviders.size() > 0) {
2229 pw.println(" Disabled Providers:");
2230 for (String i : mDisabledProviders) {
2231 pw.println(" " + i);
2232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002233 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002234 pw.append(" ");
2235 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002236 if (mMockProviders.size() > 0) {
2237 pw.println(" Mock Providers:");
2238 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002239 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 }
2241 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002242
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002243 pw.append(" fudger: ");
2244 mLocationFudger.dump(fd, pw, args);
2245
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002246 if (args.length > 0 && "short".equals(args[0])) {
2247 return;
2248 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002249 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002250 pw.print(provider.getName() + " Internal State");
2251 if (provider instanceof LocationProviderProxy) {
2252 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2253 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002254 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002255 pw.println(":");
2256 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002257 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 }
2259 }
2260}