blob: bcb7cb7730baf57d64e82e3d0bf3df44683cd360 [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;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080057import android.os.ServiceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070058import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070059import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070060import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080063import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
Dianne Hackborna06de0f2012-12-11 16:34:47 -080065import com.android.internal.app.IAppOpsService;
Mike Lockwoode97ae402010-09-29 15:23:46 -040066import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070067import com.android.internal.location.ProviderProperties;
68import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040069import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070070import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040071import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070072import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070073import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040074import com.android.server.location.LocationProviderInterface;
75import com.android.server.location.LocationProviderProxy;
76import com.android.server.location.MockProvider;
77import com.android.server.location.PassiveProvider;
78
79import java.io.FileDescriptor;
80import java.io.PrintWriter;
81import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070082import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040083import java.util.HashMap;
84import java.util.HashSet;
85import java.util.List;
86import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040087import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
89/**
90 * The service class that manages LocationProviders and issues location
91 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 */
Victoria Lease5cd731a2012-12-19 15:04:21 -080093public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -080095 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -070096
97 private static final String WAKELOCK_KEY = TAG;
98 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099
Victoria Lease37425c32012-10-16 16:08:48 -0700100 // Location resolution level: no location data whatsoever
101 private static final int RESOLUTION_LEVEL_NONE = 0;
102 // Location resolution level: coarse location data only
103 private static final int RESOLUTION_LEVEL_COARSE = 1;
104 // Location resolution level: fine location data
105 private static final int RESOLUTION_LEVEL_FINE = 2;
106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700108 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700110 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400111 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700112 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
113
114 private static final String NETWORK_LOCATION_SERVICE_ACTION =
115 "com.android.location.service.v2.NetworkLocationProvider";
116 private static final String FUSED_LOCATION_SERVICE_ACTION =
117 "com.android.location.service.FusedLocationProvider";
118
119 private static final int MSG_LOCATION_CHANGED = 1;
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
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700184 // all providers that operate over proxy, for authorizing incoming location
185 private final ArrayList<LocationProviderProxy> mProxyProviders =
186 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187
Victoria Lease38389b62012-09-30 11:44:22 -0700188 // current active user on the device - other users are denied location data
189 private int mCurrentUserId = UserHandle.USER_OWNER;
190
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700191 public LocationManagerService(Context context) {
192 super();
193 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800194 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 if (D) Log.d(TAG, "Constructed");
197
198 // most startup is deferred until systemReady()
199 }
200
201 public void systemReady() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700202 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800203 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700204
Victoria Lease5cd731a2012-12-19 15:04:21 -0800205 // fetch package manager
206 mPackageManager = mContext.getPackageManager();
207
208 // prepare wake lock
209 PowerManager powerManager =
210 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
211 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
212
213 // prepare worker thread
214 mHandlerThread = new HandlerThread(THREAD_NAME, Process.THREAD_PRIORITY_BACKGROUND);
215 mHandlerThread.start();
216 mLocationHandler = new LocationWorkerHandler(mHandlerThread.getLooper());
217
218 // prepare mLocationHandler's dependents
219 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
220 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
221 mBlacklist.init();
222 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
223
Dianne Hackbornc2293022013-02-06 23:14:49 -0800224 // Monitor for app ops mode changes.
225 AppOpsManager.Callback callback = new AppOpsManager.Callback() {
226 public void opChanged(int op, String packageName) {
227 synchronized (mLock) {
228 applyAllProviderRequirementsLocked();
229 }
230 }
231 };
232 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
233
Victoria Lease5cd731a2012-12-19 15:04:21 -0800234 // prepare providers
235 loadProvidersLocked();
236 updateProvidersLocked();
237 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700238
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700239 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700240 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700241 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700242 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800243 @Override
244 public void onChange(boolean selfChange) {
245 synchronized (mLock) {
246 updateProvidersLocked();
247 }
248 }
249 }, UserHandle.USER_ALL);
250 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700251
Victoria Lease38389b62012-09-30 11:44:22 -0700252 // listen for user change
253 IntentFilter intentFilter = new IntentFilter();
254 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
255
256 mContext.registerReceiverAsUser(new BroadcastReceiver() {
257 @Override
258 public void onReceive(Context context, Intent intent) {
259 String action = intent.getAction();
260 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
261 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
262 }
263 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800264 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700265 }
266
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500267 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
268 PackageManager pm = mContext.getPackageManager();
269 String systemPackageName = mContext.getPackageName();
270 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
271
272 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
273 new Intent(FUSED_LOCATION_SERVICE_ACTION),
274 PackageManager.GET_META_DATA, mCurrentUserId);
275 for (ResolveInfo rInfo : rInfos) {
276 String packageName = rInfo.serviceInfo.packageName;
277
278 // Check that the signature is in the list of supported sigs. If it's not in
279 // this list the standard provider binding logic won't bind to it.
280 try {
281 PackageInfo pInfo;
282 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
283 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
284 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
285 ", but has wrong signature, ignoring");
286 continue;
287 }
288 } catch (NameNotFoundException e) {
289 Log.e(TAG, "missing package: " + packageName);
290 continue;
291 }
292
293 // Get the version info
294 if (rInfo.serviceInfo.metaData == null) {
295 Log.w(TAG, "Found fused provider without metadata: " + packageName);
296 continue;
297 }
298
299 int version = rInfo.serviceInfo.metaData.getInt(
300 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
301 if (version == 0) {
302 // This should be the fallback fused location provider.
303
304 // Make sure it's in the system partition.
305 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
306 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
307 continue;
308 }
309
310 // Check that the fallback is signed the same as the OS
311 // as a proxy for coreApp="true"
312 if (pm.checkSignatures(systemPackageName, packageName)
313 != PackageManager.SIGNATURE_MATCH) {
314 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
315 + packageName);
316 continue;
317 }
318
319 // Found a valid fallback.
320 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
321 return;
322 } else {
323 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
324 }
325 }
326
327 throw new IllegalStateException("Unable to find a fused location provider that is in the "
328 + "system partition with version 0 and signed with the platform certificate. "
329 + "Such a package is needed to provide a default fused location provider in the "
330 + "event that no other fused location provider has been installed or is currently "
331 + "available. For example, coreOnly boot mode when decrypting the data "
332 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
333 }
334
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700335 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700336 // create a passive location provider, which is always enabled
337 PassiveProvider passiveProvider = new PassiveProvider(this);
338 addProviderLocked(passiveProvider);
339 mEnabledProviders.add(passiveProvider.getName());
340 mPassiveProvider = passiveProvider;
341
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700342 if (GpsLocationProvider.isSupported()) {
343 // Create a gps location provider
Victoria Lease5cd731a2012-12-19 15:04:21 -0800344 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
345 mLocationHandler.getLooper());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700346 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
347 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
348 addProviderLocked(gpsProvider);
349 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
350 }
351
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700352 /*
353 Load package name(s) containing location provider support.
354 These packages can contain services implementing location providers:
355 Geocoder Provider, Network Location Provider, and
356 Fused Location Provider. They will each be searched for
357 service components implementing these providers.
358 The location framework also has support for installation
359 of new location providers at run-time. The new package does not
360 have to be explicitly listed here, however it must have a signature
361 that matches the signature of at least one package on this list.
362 */
363 Resources resources = mContext.getResources();
364 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500365 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700366 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500367 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
368 Arrays.toString(pkgs));
369 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
370
371 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700372
373 // bind to network provider
374 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
375 mContext,
376 LocationManager.NETWORK_PROVIDER,
377 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800378 providerPackageNames, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700379 if (networkProvider != null) {
380 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
381 mProxyProviders.add(networkProvider);
382 addProviderLocked(networkProvider);
383 } else {
384 Slog.w(TAG, "no network location provider found");
385 }
386
387 // bind to fused provider
388 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
389 mContext,
390 LocationManager.FUSED_PROVIDER,
391 FUSED_LOCATION_SERVICE_ACTION,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800392 providerPackageNames, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700393 if (fusedLocationProvider != null) {
394 addProviderLocked(fusedLocationProvider);
395 mProxyProviders.add(fusedLocationProvider);
396 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700397 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700398 } else {
399 Slog.e(TAG, "no fused location provider found",
400 new IllegalStateException("Location service needs a fused location provider"));
401 }
402
403 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700404 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800405 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700406 if (mGeocodeProvider == null) {
407 Slog.e(TAG, "no geocoder provider found");
408 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700409 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700412 * Called when the device's active user changes.
413 * @param userId the new active user's UserId
414 */
415 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700416 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800417 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700418 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700419 mLastLocation.clear();
420 for (LocationProviderInterface p : mProviders) {
421 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700422 }
Victoria Lease38389b62012-09-30 11:44:22 -0700423 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700424 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700425 }
426 }
427
428 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
430 * location updates.
431 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700432 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700433 final int mUid; // uid of receiver
434 final int mPid; // pid of receiver
435 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700436 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 final ILocationListener mListener;
439 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700441
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400442 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700443
Mike Lockwood48f17512009-04-23 09:12:08 -0700444 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700446 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
447 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700450 if (listener != null) {
451 mKey = listener.asBinder();
452 } else {
453 mKey = intent;
454 }
Victoria Lease37425c32012-10-16 16:08:48 -0700455 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700456 mUid = uid;
457 mPid = pid;
458 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 }
460
461 @Override
462 public boolean equals(Object otherObj) {
463 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700464 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 }
466 return false;
467 }
468
469 @Override
470 public int hashCode() {
471 return mKey.hashCode();
472 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 @Override
475 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700476 StringBuilder s = new StringBuilder();
477 s.append("Reciever[");
478 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700480 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700482 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700484 for (String p : mUpdateRecords.keySet()) {
485 s.append(" ").append(mUpdateRecords.get(p).toString());
486 }
487 s.append("]");
488 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 }
490
491 public boolean isListener() {
492 return mListener != null;
493 }
494
495 public boolean isPendingIntent() {
496 return mPendingIntent != null;
497 }
498
499 public ILocationListener getListener() {
500 if (mListener != null) {
501 return mListener;
502 }
503 throw new IllegalStateException("Request for non-existent listener");
504 }
505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
507 if (mListener != null) {
508 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700509 synchronized (this) {
510 // synchronize to ensure incrementPendingBroadcastsLocked()
511 // is called before decrementPendingBroadcasts()
512 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700513 // call this after broadcasting so we do not increment
514 // if we throw an exeption.
515 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700516 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 } catch (RemoteException e) {
518 return false;
519 }
520 } else {
521 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800522 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
524 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700525 synchronized (this) {
526 // synchronize to ensure incrementPendingBroadcastsLocked()
527 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700528 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700529 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700530 // call this after broadcasting so we do not increment
531 // if we throw an exeption.
532 incrementPendingBroadcastsLocked();
533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 } catch (PendingIntent.CanceledException e) {
535 return false;
536 }
537 }
538 return true;
539 }
540
541 public boolean callLocationChangedLocked(Location location) {
542 if (mListener != null) {
543 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700544 synchronized (this) {
545 // synchronize to ensure incrementPendingBroadcastsLocked()
546 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800547 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700548 // call this after broadcasting so we do not increment
549 // if we throw an exeption.
550 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700551 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 } catch (RemoteException e) {
553 return false;
554 }
555 } else {
556 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800557 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700559 synchronized (this) {
560 // synchronize to ensure incrementPendingBroadcastsLocked()
561 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700562 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700563 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700564 // call this after broadcasting so we do not increment
565 // if we throw an exeption.
566 incrementPendingBroadcastsLocked();
567 }
568 } catch (PendingIntent.CanceledException e) {
569 return false;
570 }
571 }
572 return true;
573 }
574
575 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
576 if (mListener != null) {
577 try {
578 synchronized (this) {
579 // synchronize to ensure incrementPendingBroadcastsLocked()
580 // is called before decrementPendingBroadcasts()
581 if (enabled) {
582 mListener.onProviderEnabled(provider);
583 } else {
584 mListener.onProviderDisabled(provider);
585 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700586 // call this after broadcasting so we do not increment
587 // if we throw an exeption.
588 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700589 }
590 } catch (RemoteException e) {
591 return false;
592 }
593 } else {
594 Intent providerIntent = new Intent();
595 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
596 try {
597 synchronized (this) {
598 // synchronize to ensure incrementPendingBroadcastsLocked()
599 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700600 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700601 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700602 // call this after broadcasting so we do not increment
603 // if we throw an exeption.
604 incrementPendingBroadcastsLocked();
605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 } catch (PendingIntent.CanceledException e) {
607 return false;
608 }
609 }
610 return true;
611 }
612
Nick Pellyf1be6862012-05-15 10:53:42 -0700613 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700615 if (D) Log.d(TAG, "Location listener died");
616
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400617 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 removeUpdatesLocked(this);
619 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700620 synchronized (this) {
621 if (mPendingBroadcasts > 0) {
622 LocationManagerService.this.decrementPendingBroadcasts();
623 mPendingBroadcasts = 0;
624 }
625 }
626 }
627
Nick Pellye0fd6932012-07-11 10:26:13 -0700628 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700629 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
630 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400631 synchronized (this) {
632 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700633 }
634 }
635
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400636 // this must be called while synchronized by caller in a synchronized block
637 // containing the sending of the broadcaset
638 private void incrementPendingBroadcastsLocked() {
639 if (mPendingBroadcasts++ == 0) {
640 LocationManagerService.this.incrementPendingBroadcasts();
641 }
642 }
643
644 private void decrementPendingBroadcastsLocked() {
645 if (--mPendingBroadcasts == 0) {
646 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700647 }
648 }
649 }
650
Nick Pellye0fd6932012-07-11 10:26:13 -0700651 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700652 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400653 //Do not use getReceiver here as that will add the ILocationListener to
654 //the receiver list if it is not found. If it is not found then the
655 //LocationListener was removed when it had a pending broadcast and should
656 //not be added back.
657 IBinder binder = listener.asBinder();
658 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700659 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400660 synchronized (receiver) {
661 // so wakelock calls will succeed
662 long identity = Binder.clearCallingIdentity();
663 receiver.decrementPendingBroadcastsLocked();
664 Binder.restoreCallingIdentity(identity);
665 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 }
667 }
668
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700669 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400670 mProviders.add(provider);
671 mProvidersByName.put(provider.getName(), provider);
672 }
673
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700674 private void removeProviderLocked(LocationProviderInterface provider) {
675 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400676 mProviders.remove(provider);
677 mProvidersByName.remove(provider.getName());
678 }
679
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800680 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800681 * Returns "true" if access to the specified location provider is allowed by the current
682 * user's settings. Access to all location providers is forbidden to non-location-provider
683 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800684 *
685 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800686 * @return
687 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800688 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 if (mEnabledProviders.contains(provider)) {
690 return true;
691 }
692 if (mDisabledProviders.contains(provider)) {
693 return false;
694 }
695 // Use system settings
696 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697
Victoria Leaseb711d572012-10-02 13:14:11 -0700698 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 }
700
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700701 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800702 * Returns "true" if access to the specified location provider is allowed by the specified
703 * user's settings. Access to all location providers is forbidden to non-location-provider
704 * processes belonging to background users.
705 *
706 * @param provider the name of the location provider
707 * @param uid the requestor's UID
708 * @return
709 */
710 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
711 if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) {
712 return false;
713 }
714 return isAllowedByCurrentUserSettingsLocked(provider);
715 }
716
717 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700718 * Returns the permission string associated with the specified resolution level.
719 *
720 * @param resolutionLevel the resolution level
721 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700722 */
Victoria Lease37425c32012-10-16 16:08:48 -0700723 private String getResolutionPermission(int resolutionLevel) {
724 switch (resolutionLevel) {
725 case RESOLUTION_LEVEL_FINE:
726 return android.Manifest.permission.ACCESS_FINE_LOCATION;
727 case RESOLUTION_LEVEL_COARSE:
728 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
729 default:
730 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700732 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700733
Victoria Leaseda479c52012-10-15 15:24:16 -0700734 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700735 * Returns the resolution level allowed to the given PID/UID pair.
736 *
737 * @param pid the PID
738 * @param uid the UID
739 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700740 */
Victoria Lease37425c32012-10-16 16:08:48 -0700741 private int getAllowedResolutionLevel(int pid, int uid) {
742 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
743 pid, uid) == PackageManager.PERMISSION_GRANTED) {
744 return RESOLUTION_LEVEL_FINE;
745 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
746 pid, uid) == PackageManager.PERMISSION_GRANTED) {
747 return RESOLUTION_LEVEL_COARSE;
748 } else {
749 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700750 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700751 }
752
753 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700754 * Returns the resolution level allowed to the caller
755 *
756 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700757 */
Victoria Lease37425c32012-10-16 16:08:48 -0700758 private int getCallerAllowedResolutionLevel() {
759 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
760 }
761
762 /**
763 * Throw SecurityException if specified resolution level is insufficient to use geofences.
764 *
765 * @param allowedResolutionLevel resolution level allowed to caller
766 */
767 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
768 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700769 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
770 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 }
772
Victoria Lease37425c32012-10-16 16:08:48 -0700773 /**
774 * Return the minimum resolution level required to use the specified location provider.
775 *
776 * @param provider the name of the location provider
777 * @return minimum resolution level required for provider
778 */
779 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700780 if (LocationManager.GPS_PROVIDER.equals(provider) ||
781 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
782 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700783 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700784 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
785 LocationManager.FUSED_PROVIDER.equals(provider)) {
786 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700787 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700788 } else {
789 // mock providers
790 LocationProviderInterface lp = mMockProviders.get(provider);
791 if (lp != null) {
792 ProviderProperties properties = lp.getProperties();
793 if (properties != null) {
794 if (properties.mRequiresSatellite) {
795 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700796 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700797 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
798 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700799 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700800 }
801 }
802 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700803 }
Victoria Lease37425c32012-10-16 16:08:48 -0700804 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700805 }
806
Victoria Lease37425c32012-10-16 16:08:48 -0700807 /**
808 * Throw SecurityException if specified resolution level is insufficient to use the named
809 * location provider.
810 *
811 * @param allowedResolutionLevel resolution level allowed to caller
812 * @param providerName the name of the location provider
813 */
814 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
815 String providerName) {
816 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
817 if (allowedResolutionLevel < requiredResolutionLevel) {
818 switch (requiredResolutionLevel) {
819 case RESOLUTION_LEVEL_FINE:
820 throw new SecurityException("\"" + providerName + "\" location provider " +
821 "requires ACCESS_FINE_LOCATION permission.");
822 case RESOLUTION_LEVEL_COARSE:
823 throw new SecurityException("\"" + providerName + "\" location provider " +
824 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
825 default:
826 throw new SecurityException("Insufficient permission for \"" + providerName +
827 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700828 }
829 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700830 }
831
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800832 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800833 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
834 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800835 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800836 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800837 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800838 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800839 }
840 return -1;
841 }
842
843 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
844 int op = resolutionLevelToOp(allowedResolutionLevel);
845 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800846 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
847 return false;
848 }
849 }
850 return true;
851 }
852
853 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800854 int op = resolutionLevelToOp(allowedResolutionLevel);
855 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800856 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
857 return false;
858 }
859 }
860 return true;
861 }
862
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700863 /**
864 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700865 * fused, also including ones that are not permitted to
866 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700867 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700868 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700870 ArrayList<String> out;
871 synchronized (mLock) {
872 out = new ArrayList<String>(mProviders.size());
873 for (LocationProviderInterface provider : mProviders) {
874 String name = provider.getName();
875 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700876 continue;
877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 out.add(name);
879 }
880 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700881
882 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 return out;
884 }
885
Mike Lockwood03ca2162010-04-01 08:10:09 -0700886 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700887 * Return all providers by name, that match criteria and are optionally
888 * enabled.
889 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700890 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700891 @Override
892 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700893 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700894 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800895 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -0700896 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700897 try {
898 synchronized (mLock) {
899 out = new ArrayList<String>(mProviders.size());
900 for (LocationProviderInterface provider : mProviders) {
901 String name = provider.getName();
902 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700903 continue;
904 }
Victoria Lease37425c32012-10-16 16:08:48 -0700905 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -0800906 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700907 continue;
908 }
909 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
910 name, provider.getProperties(), criteria)) {
911 continue;
912 }
913 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700914 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700915 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700916 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700917 } finally {
918 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700919 }
920
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700921 if (D) Log.d(TAG, "getProviders()=" + out);
922 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700923 }
924
925 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700926 * Return the name of the best provider given a Criteria object.
927 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700928 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700929 * has been deprecated as well. So this method now uses
930 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700931 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700932 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700933 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700934 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700935
936 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700937 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700938 result = pickBest(providers);
939 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
940 return result;
941 }
942 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700943 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700944 result = pickBest(providers);
945 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
946 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700947 }
948
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700949 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700950 return null;
951 }
952
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700953 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700954 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700955 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700956 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
957 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700958 } else {
959 return providers.get(0);
960 }
961 }
962
Nick Pellye0fd6932012-07-11 10:26:13 -0700963 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700964 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
965 LocationProviderInterface p = mProvidersByName.get(provider);
966 if (p == null) {
967 throw new IllegalArgumentException("provider=" + provider);
968 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700969
970 boolean result = LocationProvider.propertiesMeetCriteria(
971 p.getName(), p.getProperties(), criteria);
972 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
973 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700974 }
975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700977 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400978 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500979 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 boolean isEnabled = p.isEnabled();
981 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -0800982 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700984 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700985 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700987 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700988 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700990 }
991 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700992 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
993 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 }
995 }
996
Victoria Leaseb711d572012-10-02 13:14:11 -0700997 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 int listeners = 0;
999
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001000 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001001 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002
1003 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001004
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1006 if (records != null) {
1007 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001008 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -07001010 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001011 // Sends a notification message to the receiver
1012 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1013 if (deadReceivers == null) {
1014 deadReceivers = new ArrayList<Receiver>();
1015 }
1016 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001018 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 }
1021 }
1022
1023 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001024 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 removeUpdatesLocked(deadReceivers.get(i));
1026 }
1027 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 if (enabled) {
1030 p.enable();
1031 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001032 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 }
1034 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 }
1038
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001039 private void applyRequirementsLocked(String provider) {
1040 LocationProviderInterface p = mProvidersByName.get(provider);
1041 if (p == null) return;
1042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001044 WorkSource worksource = new WorkSource();
1045 ProviderRequest providerRequest = new ProviderRequest();
1046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001048 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001049 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001050 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1051 record.mReceiver.mAllowedResolutionLevel)) {
1052 LocationRequest locationRequest = record.mRequest;
1053 providerRequest.locationRequests.add(locationRequest);
1054 if (locationRequest.getInterval() < providerRequest.interval) {
1055 providerRequest.reportLocation = true;
1056 providerRequest.interval = locationRequest.getInterval();
1057 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001058 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001059 }
1060 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001061
1062 if (providerRequest.reportLocation) {
1063 // calculate who to blame for power
1064 // This is somewhat arbitrary. We pick a threshold interval
1065 // that is slightly higher that the minimum interval, and
1066 // spread the blame across all applications with a request
1067 // under that threshold.
1068 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1069 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001070 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001071 LocationRequest locationRequest = record.mRequest;
1072 if (locationRequest.getInterval() <= thresholdInterval) {
Dianne Hackborn002a54e2013-01-10 17:34:55 -08001073 worksource.add(record.mReceiver.mUid, record.mReceiver.mPackageName);
Victoria Leaseb711d572012-10-02 13:14:11 -07001074 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001075 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
1078 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001079
1080 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1081 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 }
1083
1084 private class UpdateRecord {
1085 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001086 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001088 Location mLastFixBroadcast;
1089 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090
1091 /**
1092 * Note: must be constructed with lock held.
1093 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001094 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001096 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098
1099 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1100 if (records == null) {
1101 records = new ArrayList<UpdateRecord>();
1102 mRecordsByProvider.put(provider, records);
1103 }
1104 if (!records.contains(this)) {
1105 records.add(this);
1106 }
1107 }
1108
1109 /**
1110 * Method to be called when a record will no longer be used. Calling this multiple times
1111 * must have the same effect as calling it once.
1112 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001113 void disposeLocked(boolean removeReceiver) {
1114 // remove from mRecordsByProvider
1115 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1116 if (globalRecords != null) {
1117 globalRecords.remove(this);
1118 }
1119
1120 if (!removeReceiver) return; // the caller will handle the rest
1121
1122 // remove from Receiver#mUpdateRecords
1123 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1124 if (receiverRecords != null) {
1125 receiverRecords.remove(this.mProvider);
1126
1127 // and also remove the Receiver if it has no more update records
1128 if (removeReceiver && receiverRecords.size() == 0) {
1129 removeUpdatesLocked(mReceiver);
1130 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001131 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 }
1133
1134 @Override
1135 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001136 StringBuilder s = new StringBuilder();
1137 s.append("UpdateRecord[");
1138 s.append(mProvider);
1139 s.append(' ').append(mReceiver.mPackageName).append('(');
1140 s.append(mReceiver.mUid).append(')');
1141 s.append(' ').append(mRequest);
1142 s.append(']');
1143 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 }
1146
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001147 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001148 IBinder binder = listener.asBinder();
1149 Receiver receiver = mReceivers.get(binder);
1150 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001151 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001152 mReceivers.put(binder, receiver);
1153
1154 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001155 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001156 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001157 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001158 return null;
1159 }
1160 }
1161 return receiver;
1162 }
1163
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001164 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001165 Receiver receiver = mReceivers.get(intent);
1166 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001167 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001168 mReceivers.put(intent, receiver);
1169 }
1170 return receiver;
1171 }
1172
Victoria Lease37425c32012-10-16 16:08:48 -07001173 /**
1174 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1175 * and consistency requirements.
1176 *
1177 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001178 * @return a version of request that meets the given resolution and consistency requirements
1179 * @hide
1180 */
1181 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1182 LocationRequest sanitizedRequest = new LocationRequest(request);
1183 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1184 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001185 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001186 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001187 break;
1188 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001189 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001190 break;
1191 }
1192 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001193 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1194 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001195 }
Victoria Lease37425c32012-10-16 16:08:48 -07001196 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1197 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001198 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001199 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001200 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001201 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001202 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001203 }
Victoria Lease37425c32012-10-16 16:08:48 -07001204 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001205 }
1206
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001207 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001208 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001209 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001210 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001211 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001212 String[] packages = mPackageManager.getPackagesForUid(uid);
1213 if (packages == null) {
1214 throw new SecurityException("invalid UID " + uid);
1215 }
1216 for (String pkg : packages) {
1217 if (packageName.equals(pkg)) return;
1218 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001219 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001220 }
1221
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 private void checkPendingIntent(PendingIntent intent) {
1223 if (intent == null) {
1224 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001225 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001226 }
1227
1228 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1229 int pid, int uid, String packageName) {
1230 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001231 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001232 } else if (intent != null && listener != null) {
1233 throw new IllegalArgumentException("cannot register both listener and intent");
1234 } else if (intent != null) {
1235 checkPendingIntent(intent);
1236 return getReceiver(intent, pid, uid, packageName);
1237 } else {
1238 return getReceiver(listener, pid, uid, packageName);
1239 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001240 }
1241
Nick Pellye0fd6932012-07-11 10:26:13 -07001242 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001243 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1244 PendingIntent intent, String packageName) {
1245 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1246 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001247 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1248 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1249 request.getProvider());
1250 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001252 final int pid = Binder.getCallingPid();
1253 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001254 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 long identity = Binder.clearCallingIdentity();
1256 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001257 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1258 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001259 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001260 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1261
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001262 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001263 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001264 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 } finally {
1266 Binder.restoreCallingIdentity(identity);
1267 }
1268 }
1269
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001270 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1271 int pid, int uid, String packageName) {
1272 // Figure out the provider. Either its explicitly request (legacy use cases), or
1273 // use the fused provider
1274 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1275 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001276 if (name == null) {
1277 throw new IllegalArgumentException("provider name must not be null");
1278 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001279 LocationProviderInterface provider = mProvidersByName.get(name);
1280 if (provider == null) {
1281 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1282 }
1283
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001284 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1285 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001286
1287 UpdateRecord record = new UpdateRecord(name, request, receiver);
1288 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1289 if (oldRecord != null) {
1290 oldRecord.disposeLocked(false);
1291 }
1292
Victoria Lease09eeaec2013-02-05 11:34:13 -08001293 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001294 if (isProviderEnabled) {
1295 applyRequirementsLocked(name);
1296 } else {
1297 // Notify the listener that updates are currently disabled
1298 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 }
1300 }
1301
Nick Pellye0fd6932012-07-11 10:26:13 -07001302 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001303 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1304 String packageName) {
1305 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001306
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001307 final int pid = Binder.getCallingPid();
1308 final int uid = Binder.getCallingUid();
1309 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1310
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001311 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001312 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001314 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001315 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001317 } finally {
1318 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 }
1320 }
1321
1322 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001323 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324
1325 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1326 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1327 synchronized (receiver) {
1328 if (receiver.mPendingBroadcasts > 0) {
1329 decrementPendingBroadcasts();
1330 receiver.mPendingBroadcasts = 0;
1331 }
1332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 }
1334
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001335 // Record which providers were associated with this listener
1336 HashSet<String> providers = new HashSet<String>();
1337 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1338 if (oldRecords != null) {
1339 // Call dispose() on the obsolete update records.
1340 for (UpdateRecord record : oldRecords.values()) {
1341 record.disposeLocked(false);
1342 }
1343 // Accumulate providers
1344 providers.addAll(oldRecords.keySet());
1345 }
1346
1347 // update provider
1348 for (String provider : providers) {
1349 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001350 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001351 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 }
1353
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001354 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 }
1356 }
1357
Dianne Hackbornc2293022013-02-06 23:14:49 -08001358 private void applyAllProviderRequirementsLocked() {
1359 for (LocationProviderInterface p : mProviders) {
1360 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001361 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001362 continue;
1363 }
1364
1365 applyRequirementsLocked(p.getName());
1366 }
1367 }
1368
Nick Pellye0fd6932012-07-11 10:26:13 -07001369 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001370 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001371 if (D) Log.d(TAG, "getLastLocation: " + request);
1372 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001373 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001374 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001375 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1376 request.getProvider());
1377 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001378
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001379 final int uid = Binder.getCallingUid();
1380 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001381 try {
1382 if (mBlacklist.isBlacklisted(packageName)) {
1383 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1384 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001385 return null;
1386 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001387
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001388 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1389 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1390 packageName);
1391 return null;
1392 }
1393
Victoria Leaseb711d572012-10-02 13:14:11 -07001394 synchronized (mLock) {
1395 // Figure out the provider. Either its explicitly request (deprecated API's),
1396 // or use the fused provider
1397 String name = request.getProvider();
1398 if (name == null) name = LocationManager.FUSED_PROVIDER;
1399 LocationProviderInterface provider = mProvidersByName.get(name);
1400 if (provider == null) return null;
1401
Victoria Lease09eeaec2013-02-05 11:34:13 -08001402 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001403
1404 Location location = mLastLocation.get(name);
1405 if (location == null) {
1406 return null;
1407 }
Victoria Lease37425c32012-10-16 16:08:48 -07001408 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001409 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1410 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001411 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001412 }
Victoria Lease37425c32012-10-16 16:08:48 -07001413 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001414 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001415 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001416 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001417 return null;
1418 } finally {
1419 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001420 }
1421 }
1422
1423 @Override
1424 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1425 String packageName) {
1426 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001427 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1428 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001429 checkPendingIntent(intent);
1430 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001431 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1432 request.getProvider());
1433 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001434
Victoria Lease37425c32012-10-16 16:08:48 -07001435 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001436
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001437 // geo-fence manager uses the public location API, need to clear identity
1438 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001439 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1440 // temporary measure until geofences work for secondary users
1441 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1442 return;
1443 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001444 long identity = Binder.clearCallingIdentity();
1445 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001446 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1447 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001448 } finally {
1449 Binder.restoreCallingIdentity(identity);
1450 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001451 }
1452
1453 @Override
1454 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001455 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001456 checkPendingIntent(intent);
1457 checkPackageName(packageName);
1458
1459 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1460
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001461 // geo-fence manager uses the public location API, need to clear identity
1462 long identity = Binder.clearCallingIdentity();
1463 try {
1464 mGeofenceManager.removeFence(geofence, intent);
1465 } finally {
1466 Binder.restoreCallingIdentity(identity);
1467 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001468 }
1469
1470
1471 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001472 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001473 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 return false;
1475 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001476 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1477 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001478 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001480 final int uid = Binder.getCallingUid();
1481 final long ident = Binder.clearCallingIdentity();
1482 try {
Victoria Lease3d5173d2013-02-05 16:07:32 -08001483 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001484 return false;
1485 }
1486 } finally {
1487 Binder.restoreCallingIdentity(ident);
1488 }
1489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001491 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001493 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 return false;
1495 }
1496 return true;
1497 }
1498
Nick Pellye0fd6932012-07-11 10:26:13 -07001499 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001501 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001502 try {
1503 mGpsStatusProvider.removeGpsStatusListener(listener);
1504 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001505 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 }
1508 }
1509
Nick Pellye0fd6932012-07-11 10:26:13 -07001510 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001512 if (provider == null) {
1513 // throw NullPointerException to remain compatible with previous implementation
1514 throw new NullPointerException();
1515 }
Victoria Lease37425c32012-10-16 16:08:48 -07001516 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1517 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001520 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 != PackageManager.PERMISSION_GRANTED)) {
1522 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1523 }
1524
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001525 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001526 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001527 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001528
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001529 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 }
1531 }
1532
Nick Pellye0fd6932012-07-11 10:26:13 -07001533 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001534 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001535 if (Binder.getCallingUid() != Process.myUid()) {
1536 throw new SecurityException(
1537 "calling sendNiResponse from outside of the system is not allowed");
1538 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001539 try {
1540 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001541 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001542 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001543 return false;
1544 }
1545 }
1546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001548 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001549 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 * accessed by the caller
1551 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001552 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001553 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001554 if (mProvidersByName.get(provider) == null) {
1555 return null;
1556 }
1557
Victoria Lease37425c32012-10-16 16:08:48 -07001558 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1559 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001561 LocationProviderInterface p;
1562 synchronized (mLock) {
1563 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 }
1565
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001566 if (p == null) return null;
1567 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 }
1569
Nick Pellye0fd6932012-07-11 10:26:13 -07001570 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001572 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1573 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001574 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1575
Victoria Lease09eeaec2013-02-05 11:34:13 -08001576 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001577 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001578 try {
1579 synchronized (mLock) {
1580 LocationProviderInterface p = mProvidersByName.get(provider);
1581 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001582
Victoria Lease09eeaec2013-02-05 11:34:13 -08001583 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001584 }
1585 } finally {
1586 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001587 }
1588 }
1589
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001590 /**
1591 * Returns "true" if the UID belongs to a bound location provider.
1592 *
1593 * @param uid the uid
1594 * @return true if uid belongs to a bound location provider
1595 */
1596 private boolean isUidALocationProvider(int uid) {
1597 if (uid == Process.SYSTEM_UID) {
1598 return true;
1599 }
1600 if (mGeocodeProvider != null) {
1601 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1602 }
1603 for (LocationProviderProxy proxy : mProxyProviders) {
1604 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
1605 }
1606 return false;
1607 }
1608
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001609 private void checkCallerIsProvider() {
1610 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1611 == PackageManager.PERMISSION_GRANTED) {
1612 return;
1613 }
1614
1615 // Previously we only used the INSTALL_LOCATION_PROVIDER
1616 // check. But that is system or signature
1617 // protection level which is not flexible enough for
1618 // providers installed oustide the system image. So
1619 // also allow providers with a UID matching the
1620 // currently bound package name
1621
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001622 if (isUidALocationProvider(Binder.getCallingUid())) {
1623 return;
1624 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001625
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001626 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1627 "or UID of a currently bound location provider");
1628 }
1629
1630 private boolean doesPackageHaveUid(int uid, String packageName) {
1631 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 return false;
1633 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001634 try {
1635 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1636 if (appInfo.uid != uid) {
1637 return false;
1638 }
1639 } catch (NameNotFoundException e) {
1640 return false;
1641 }
1642 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 }
1644
Nick Pellye0fd6932012-07-11 10:26:13 -07001645 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001646 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001647 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001648
Nick Pelly2eeeec22012-07-18 13:13:37 -07001649 if (!location.isComplete()) {
1650 Log.w(TAG, "Dropping incomplete location: " + location);
1651 return;
1652 }
1653
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001654 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1655 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001656 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001657 mLocationHandler.sendMessageAtFrontOfQueue(m);
1658 }
1659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660
Laurent Tu75defb62012-11-01 16:21:52 -07001661 private static boolean shouldBroadcastSafe(
1662 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 // Always broadcast the first update
1664 if (lastLoc == null) {
1665 return true;
1666 }
1667
Nick Pellyf1be6862012-05-15 10:53:42 -07001668 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001669 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001670 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001671 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 return false;
1673 }
1674
1675 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001676 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 if (minDistance > 0.0) {
1678 if (loc.distanceTo(lastLoc) <= minDistance) {
1679 return false;
1680 }
1681 }
1682
Laurent Tu75defb62012-11-01 16:21:52 -07001683 // Check whether sufficient number of udpates is left
1684 if (record.mRequest.getNumUpdates() <= 0) {
1685 return false;
1686 }
1687
1688 // Check whether the expiry date has passed
1689 if (record.mRequest.getExpireAt() < now) {
1690 return false;
1691 }
1692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 return true;
1694 }
1695
Mike Lockwooda4903f22010-02-17 06:42:23 -05001696 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001697 if (D) Log.d(TAG, "incoming location: " + location);
1698
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001699 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001700 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701
Laurent Tu60ec50a2012-10-04 17:00:10 -07001702 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001703 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001704 if (p == null) return;
1705
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001706 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001707 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1708 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001709 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001710 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001711 lastLocation = new Location(provider);
1712 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001713 } else {
1714 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1715 if (noGPSLocation == null && lastNoGPSLocation != null) {
1716 // New location has no no-GPS location: adopt last no-GPS location. This is set
1717 // directly into location because we do not want to notify COARSE clients.
1718 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1719 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001720 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001721 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722
Laurent Tu60ec50a2012-10-04 17:00:10 -07001723 // Skip if there are no UpdateRecords for this provider.
1724 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1725 if (records == null || records.size() == 0) return;
1726
Victoria Lease09016ab2012-09-16 12:33:15 -07001727 // Fetch coarse location
1728 Location coarseLocation = null;
1729 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1730 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1731 }
1732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 // Fetch latest status update time
1734 long newStatusUpdateTime = p.getStatusUpdateTime();
1735
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001736 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 Bundle extras = new Bundle();
1738 int status = p.getStatus(extras);
1739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001741 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001744 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001746 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001747
Victoria Lease269518e2012-10-29 08:25:39 -07001748 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1749 if (receiverUserId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001750 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001751 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001752 " (current user: " + mCurrentUserId + ", app: " +
1753 receiver.mPackageName + ")");
1754 }
1755 continue;
1756 }
1757
Nick Pelly4035f5a2012-08-17 14:43:49 -07001758 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1759 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1760 receiver.mPackageName);
1761 continue;
1762 }
1763
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001764 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
1765 receiver.mAllowedResolutionLevel)) {
1766 if (D) Log.d(TAG, "skipping loc update for no op app: " +
1767 receiver.mPackageName);
1768 continue;
1769 }
1770
Victoria Lease09016ab2012-09-16 12:33:15 -07001771 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001772 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1773 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001774 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001775 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001776 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001777 if (notifyLocation != null) {
1778 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001779 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001780 if (lastLoc == null) {
1781 lastLoc = new Location(notifyLocation);
1782 r.mLastFixBroadcast = lastLoc;
1783 } else {
1784 lastLoc.set(notifyLocation);
1785 }
1786 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1787 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1788 receiverDead = true;
1789 }
Laurent Tu75defb62012-11-01 16:21:52 -07001790 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 }
1792 }
1793
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001794 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001796 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001798 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001800 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001801 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001802 }
1803 }
1804
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001805 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001806 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001807 if (deadUpdateRecords == null) {
1808 deadUpdateRecords = new ArrayList<UpdateRecord>();
1809 }
1810 deadUpdateRecords.add(r);
1811 }
1812 // track dead receivers
1813 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001814 if (deadReceivers == null) {
1815 deadReceivers = new ArrayList<Receiver>();
1816 }
1817 if (!deadReceivers.contains(receiver)) {
1818 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 }
1820 }
1821 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001822
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001823 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001825 for (Receiver receiver : deadReceivers) {
1826 removeUpdatesLocked(receiver);
1827 }
1828 }
1829 if (deadUpdateRecords != null) {
1830 for (UpdateRecord r : deadUpdateRecords) {
1831 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 }
Victoria Lease8b38b292012-12-04 15:04:43 -08001833 applyRequirementsLocked(provider);
1834 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 }
1836
1837 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001838 public LocationWorkerHandler(Looper looper) {
1839 super(looper, null, true);
1840 }
1841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 @Override
1843 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001844 switch (msg.what) {
1845 case MSG_LOCATION_CHANGED:
1846 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1847 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001848 }
1849 }
1850 }
1851
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001852 private boolean isMockProvider(String provider) {
1853 synchronized (mLock) {
1854 return mMockProviders.containsKey(provider);
1855 }
1856 }
1857
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001858 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001859 // create a working copy of the incoming Location so that the service can modify it without
1860 // disturbing the caller's copy
1861 Location myLocation = new Location(location);
1862 String provider = myLocation.getProvider();
1863
1864 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
1865 // bit if location did not come from a mock provider because passive/fused providers can
1866 // forward locations from mock providers, and should not grant them legitimacy in doing so.
1867 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
1868 myLocation.setIsFromMockProvider(true);
1869 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08001870
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001871 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001872 if (isAllowedByCurrentUserSettingsLocked(provider)) {
1873 if (!passive) {
1874 // notify passive provider of the new location
1875 mPassiveProvider.updateLocation(myLocation);
1876 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001877 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001880 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881
Mike Lockwoode97ae402010-09-29 15:23:46 -04001882 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1883 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001884 public void onPackageDisappeared(String packageName, int reason) {
1885 // remove all receivers associated with this package name
1886 synchronized (mLock) {
1887 ArrayList<Receiver> deadReceivers = null;
1888
1889 for (Receiver receiver : mReceivers.values()) {
1890 if (receiver.mPackageName.equals(packageName)) {
1891 if (deadReceivers == null) {
1892 deadReceivers = new ArrayList<Receiver>();
1893 }
1894 deadReceivers.add(receiver);
1895 }
1896 }
1897
1898 // perform removal outside of mReceivers loop
1899 if (deadReceivers != null) {
1900 for (Receiver receiver : deadReceivers) {
1901 removeUpdatesLocked(receiver);
1902 }
1903 }
1904 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001905 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001906 };
1907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 // Wake locks
1909
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001910 private void incrementPendingBroadcasts() {
1911 synchronized (mWakeLock) {
1912 if (mPendingBroadcasts++ == 0) {
1913 try {
1914 mWakeLock.acquire();
1915 log("Acquired wakelock");
1916 } catch (Exception e) {
1917 // This is to catch a runtime exception thrown when we try to release an
1918 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001919 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001920 }
1921 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001922 }
1923 }
1924
1925 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001926 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001927 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001928 try {
1929 // Release wake lock
1930 if (mWakeLock.isHeld()) {
1931 mWakeLock.release();
1932 log("Released wakelock");
1933 } else {
1934 log("Can't release wakelock again!");
1935 }
1936 } catch (Exception e) {
1937 // This is to catch a runtime exception thrown when we try to release an
1938 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001939 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001940 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001941 }
1942 }
1943 }
1944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 // Geocoder
1946
Nick Pellye0fd6932012-07-11 10:26:13 -07001947 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001948 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001949 return mGeocodeProvider != null;
1950 }
1951
Nick Pellye0fd6932012-07-11 10:26:13 -07001952 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001954 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001955 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001956 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1957 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001959 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 }
1961
Mike Lockwooda55c3212009-04-15 11:10:11 -04001962
Nick Pellye0fd6932012-07-11 10:26:13 -07001963 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001964 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001965 double lowerLeftLatitude, double lowerLeftLongitude,
1966 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001967 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001968
1969 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001970 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1971 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1972 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001974 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 }
1976
1977 // Mock Providers
1978
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 private void checkMockPermissionsSafe() {
1980 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1981 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1982 if (!allowMocks) {
1983 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1984 }
1985
1986 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1987 PackageManager.PERMISSION_GRANTED) {
1988 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001989 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 }
1991
Nick Pellye0fd6932012-07-11 10:26:13 -07001992 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001993 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 checkMockPermissionsSafe();
1995
Mike Lockwooda4903f22010-02-17 06:42:23 -05001996 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1997 throw new IllegalArgumentException("Cannot mock the passive location provider");
1998 }
1999
Mike Lockwood86328a92009-10-23 08:38:25 -04002000 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002001 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002002 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002003 // remove the real provider if we are replacing GPS or network provider
2004 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002005 || LocationManager.NETWORK_PROVIDER.equals(name)
2006 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002007 LocationProviderInterface p = mProvidersByName.get(name);
2008 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002009 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002010 }
2011 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002012 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2014 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002015 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002016 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002017 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 updateProvidersLocked();
2019 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002020 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 }
2022
Nick Pellye0fd6932012-07-11 10:26:13 -07002023 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 public void removeTestProvider(String provider) {
2025 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002026 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09002027 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002028 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2030 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002031 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002032 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002033
2034 // reinstate real provider if available
2035 LocationProviderInterface realProvider = mRealProviders.get(provider);
2036 if (realProvider != null) {
2037 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002038 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002039 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002041 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002042 }
2043 }
2044
Nick Pellye0fd6932012-07-11 10:26:13 -07002045 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002046 public void setTestProviderLocation(String provider, Location loc) {
2047 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002048 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002049 MockProvider mockProvider = mMockProviders.get(provider);
2050 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2052 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002053 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2054 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002055 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002056 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002057 }
2058 }
2059
Nick Pellye0fd6932012-07-11 10:26:13 -07002060 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 public void clearTestProviderLocation(String provider) {
2062 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002063 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002064 MockProvider mockProvider = mMockProviders.get(provider);
2065 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2067 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002068 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 }
2070 }
2071
Nick Pellye0fd6932012-07-11 10:26:13 -07002072 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 public void setTestProviderEnabled(String provider, boolean enabled) {
2074 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002075 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002076 MockProvider mockProvider = mMockProviders.get(provider);
2077 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2079 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002080 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002081 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002082 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 mEnabledProviders.add(provider);
2084 mDisabledProviders.remove(provider);
2085 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002086 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 mEnabledProviders.remove(provider);
2088 mDisabledProviders.add(provider);
2089 }
2090 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002091 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002092 }
2093 }
2094
Nick Pellye0fd6932012-07-11 10:26:13 -07002095 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002096 public void clearTestProviderEnabled(String provider) {
2097 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002098 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002099 MockProvider mockProvider = mMockProviders.get(provider);
2100 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002101 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2102 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002103 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 mEnabledProviders.remove(provider);
2105 mDisabledProviders.remove(provider);
2106 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002107 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 }
2109 }
2110
Nick Pellye0fd6932012-07-11 10:26:13 -07002111 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002112 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2113 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002114 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002115 MockProvider mockProvider = mMockProviders.get(provider);
2116 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2118 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002119 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 }
2121 }
2122
Nick Pellye0fd6932012-07-11 10:26:13 -07002123 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002124 public void clearTestProviderStatus(String provider) {
2125 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002126 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002127 MockProvider mockProvider = mMockProviders.get(provider);
2128 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002129 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2130 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002131 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 }
2133 }
2134
2135 private void log(String log) {
2136 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002137 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002138 }
2139 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002140
2141 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002142 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2143 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2144 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002145 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002146 + Binder.getCallingPid()
2147 + ", uid=" + Binder.getCallingUid());
2148 return;
2149 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002150
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002151 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002153 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002154 for (Receiver receiver : mReceivers.values()) {
2155 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002157 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002158 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2159 pw.println(" " + entry.getKey() + ":");
2160 for (UpdateRecord record : entry.getValue()) {
2161 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002162 }
2163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002165 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2166 String provider = entry.getKey();
2167 Location location = entry.getValue();
2168 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002169 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002170
Nick Pellye0fd6932012-07-11 10:26:13 -07002171 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002173 if (mEnabledProviders.size() > 0) {
2174 pw.println(" Enabled Providers:");
2175 for (String i : mEnabledProviders) {
2176 pw.println(" " + i);
2177 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 }
2180 if (mDisabledProviders.size() > 0) {
2181 pw.println(" Disabled Providers:");
2182 for (String i : mDisabledProviders) {
2183 pw.println(" " + i);
2184 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002185 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002186 pw.append(" ");
2187 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 if (mMockProviders.size() > 0) {
2189 pw.println(" Mock Providers:");
2190 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002191 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002192 }
2193 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002194
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002195 pw.append(" fudger: ");
2196 mLocationFudger.dump(fd, pw, args);
2197
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002198 if (args.length > 0 && "short".equals(args[0])) {
2199 return;
2200 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002201 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002202 pw.print(provider.getName() + " Internal State");
2203 if (provider instanceof LocationProviderProxy) {
2204 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2205 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002206 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002207 pw.println(":");
2208 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002209 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 }
2211 }
2212}