blob: 9aef508f7513cf791ca0ee6b12d18c3f47c23790 [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";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070095 public static final boolean D = false;
96
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
224 // prepare providers
225 loadProvidersLocked();
226 updateProvidersLocked();
227 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700228
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700229 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700230 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700231 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700232 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800233 @Override
234 public void onChange(boolean selfChange) {
235 synchronized (mLock) {
236 updateProvidersLocked();
237 }
238 }
239 }, UserHandle.USER_ALL);
240 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700241
Victoria Lease38389b62012-09-30 11:44:22 -0700242 // listen for user change
243 IntentFilter intentFilter = new IntentFilter();
244 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
245
246 mContext.registerReceiverAsUser(new BroadcastReceiver() {
247 @Override
248 public void onReceive(Context context, Intent intent) {
249 String action = intent.getAction();
250 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
251 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
252 }
253 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800254 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700255 }
256
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500257 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
258 PackageManager pm = mContext.getPackageManager();
259 String systemPackageName = mContext.getPackageName();
260 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
261
262 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
263 new Intent(FUSED_LOCATION_SERVICE_ACTION),
264 PackageManager.GET_META_DATA, mCurrentUserId);
265 for (ResolveInfo rInfo : rInfos) {
266 String packageName = rInfo.serviceInfo.packageName;
267
268 // Check that the signature is in the list of supported sigs. If it's not in
269 // this list the standard provider binding logic won't bind to it.
270 try {
271 PackageInfo pInfo;
272 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
273 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
274 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
275 ", but has wrong signature, ignoring");
276 continue;
277 }
278 } catch (NameNotFoundException e) {
279 Log.e(TAG, "missing package: " + packageName);
280 continue;
281 }
282
283 // Get the version info
284 if (rInfo.serviceInfo.metaData == null) {
285 Log.w(TAG, "Found fused provider without metadata: " + packageName);
286 continue;
287 }
288
289 int version = rInfo.serviceInfo.metaData.getInt(
290 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
291 if (version == 0) {
292 // This should be the fallback fused location provider.
293
294 // Make sure it's in the system partition.
295 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
296 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
297 continue;
298 }
299
300 // Check that the fallback is signed the same as the OS
301 // as a proxy for coreApp="true"
302 if (pm.checkSignatures(systemPackageName, packageName)
303 != PackageManager.SIGNATURE_MATCH) {
304 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
305 + packageName);
306 continue;
307 }
308
309 // Found a valid fallback.
310 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
311 return;
312 } else {
313 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
314 }
315 }
316
317 throw new IllegalStateException("Unable to find a fused location provider that is in the "
318 + "system partition with version 0 and signed with the platform certificate. "
319 + "Such a package is needed to provide a default fused location provider in the "
320 + "event that no other fused location provider has been installed or is currently "
321 + "available. For example, coreOnly boot mode when decrypting the data "
322 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
323 }
324
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700325 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700326 // create a passive location provider, which is always enabled
327 PassiveProvider passiveProvider = new PassiveProvider(this);
328 addProviderLocked(passiveProvider);
329 mEnabledProviders.add(passiveProvider.getName());
330 mPassiveProvider = passiveProvider;
331
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700332 if (GpsLocationProvider.isSupported()) {
333 // Create a gps location provider
Victoria Lease5cd731a2012-12-19 15:04:21 -0800334 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
335 mLocationHandler.getLooper());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700336 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
337 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
338 addProviderLocked(gpsProvider);
339 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
340 }
341
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700342 /*
343 Load package name(s) containing location provider support.
344 These packages can contain services implementing location providers:
345 Geocoder Provider, Network Location Provider, and
346 Fused Location Provider. They will each be searched for
347 service components implementing these providers.
348 The location framework also has support for installation
349 of new location providers at run-time. The new package does not
350 have to be explicitly listed here, however it must have a signature
351 that matches the signature of at least one package on this list.
352 */
353 Resources resources = mContext.getResources();
354 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500355 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700356 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500357 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
358 Arrays.toString(pkgs));
359 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
360
361 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700362
363 // bind to network provider
364 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
365 mContext,
366 LocationManager.NETWORK_PROVIDER,
367 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800368 providerPackageNames, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700369 if (networkProvider != null) {
370 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
371 mProxyProviders.add(networkProvider);
372 addProviderLocked(networkProvider);
373 } else {
374 Slog.w(TAG, "no network location provider found");
375 }
376
377 // bind to fused provider
378 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
379 mContext,
380 LocationManager.FUSED_PROVIDER,
381 FUSED_LOCATION_SERVICE_ACTION,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800382 providerPackageNames, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700383 if (fusedLocationProvider != null) {
384 addProviderLocked(fusedLocationProvider);
385 mProxyProviders.add(fusedLocationProvider);
386 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700387 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700388 } else {
389 Slog.e(TAG, "no fused location provider found",
390 new IllegalStateException("Location service needs a fused location provider"));
391 }
392
393 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700394 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800395 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700396 if (mGeocodeProvider == null) {
397 Slog.e(TAG, "no geocoder provider found");
398 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700399 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700402 * Called when the device's active user changes.
403 * @param userId the new active user's UserId
404 */
405 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700406 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800407 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700408 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700409 mLastLocation.clear();
410 for (LocationProviderInterface p : mProviders) {
411 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700412 }
Victoria Lease38389b62012-09-30 11:44:22 -0700413 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700414 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700415 }
416 }
417
418 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
420 * location updates.
421 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700422 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700423 final int mUid; // uid of receiver
424 final int mPid; // pid of receiver
425 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700426 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 final ILocationListener mListener;
429 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700431
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400432 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700433
Mike Lockwood48f17512009-04-23 09:12:08 -0700434 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700436 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
437 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700440 if (listener != null) {
441 mKey = listener.asBinder();
442 } else {
443 mKey = intent;
444 }
Victoria Lease37425c32012-10-16 16:08:48 -0700445 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700446 mUid = uid;
447 mPid = pid;
448 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 }
450
451 @Override
452 public boolean equals(Object otherObj) {
453 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700454 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 }
456 return false;
457 }
458
459 @Override
460 public int hashCode() {
461 return mKey.hashCode();
462 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 @Override
465 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700466 StringBuilder s = new StringBuilder();
467 s.append("Reciever[");
468 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700470 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700472 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700474 for (String p : mUpdateRecords.keySet()) {
475 s.append(" ").append(mUpdateRecords.get(p).toString());
476 }
477 s.append("]");
478 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 }
480
481 public boolean isListener() {
482 return mListener != null;
483 }
484
485 public boolean isPendingIntent() {
486 return mPendingIntent != null;
487 }
488
489 public ILocationListener getListener() {
490 if (mListener != null) {
491 return mListener;
492 }
493 throw new IllegalStateException("Request for non-existent listener");
494 }
495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
497 if (mListener != null) {
498 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700499 synchronized (this) {
500 // synchronize to ensure incrementPendingBroadcastsLocked()
501 // is called before decrementPendingBroadcasts()
502 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700503 // call this after broadcasting so we do not increment
504 // if we throw an exeption.
505 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 } catch (RemoteException e) {
508 return false;
509 }
510 } else {
511 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800512 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
514 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700515 synchronized (this) {
516 // synchronize to ensure incrementPendingBroadcastsLocked()
517 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700518 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700519 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700520 // call this after broadcasting so we do not increment
521 // if we throw an exeption.
522 incrementPendingBroadcastsLocked();
523 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 } catch (PendingIntent.CanceledException e) {
525 return false;
526 }
527 }
528 return true;
529 }
530
531 public boolean callLocationChangedLocked(Location location) {
532 if (mListener != null) {
533 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700534 synchronized (this) {
535 // synchronize to ensure incrementPendingBroadcastsLocked()
536 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800537 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700538 // call this after broadcasting so we do not increment
539 // if we throw an exeption.
540 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 } catch (RemoteException e) {
543 return false;
544 }
545 } else {
546 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800547 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700549 synchronized (this) {
550 // synchronize to ensure incrementPendingBroadcastsLocked()
551 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700552 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700553 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700554 // call this after broadcasting so we do not increment
555 // if we throw an exeption.
556 incrementPendingBroadcastsLocked();
557 }
558 } catch (PendingIntent.CanceledException e) {
559 return false;
560 }
561 }
562 return true;
563 }
564
565 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
566 if (mListener != null) {
567 try {
568 synchronized (this) {
569 // synchronize to ensure incrementPendingBroadcastsLocked()
570 // is called before decrementPendingBroadcasts()
571 if (enabled) {
572 mListener.onProviderEnabled(provider);
573 } else {
574 mListener.onProviderDisabled(provider);
575 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700576 // call this after broadcasting so we do not increment
577 // if we throw an exeption.
578 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700579 }
580 } catch (RemoteException e) {
581 return false;
582 }
583 } else {
584 Intent providerIntent = new Intent();
585 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
586 try {
587 synchronized (this) {
588 // synchronize to ensure incrementPendingBroadcastsLocked()
589 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700590 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700591 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700592 // call this after broadcasting so we do not increment
593 // if we throw an exeption.
594 incrementPendingBroadcastsLocked();
595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 } catch (PendingIntent.CanceledException e) {
597 return false;
598 }
599 }
600 return true;
601 }
602
Nick Pellyf1be6862012-05-15 10:53:42 -0700603 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700605 if (D) Log.d(TAG, "Location listener died");
606
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400607 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 removeUpdatesLocked(this);
609 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700610 synchronized (this) {
611 if (mPendingBroadcasts > 0) {
612 LocationManagerService.this.decrementPendingBroadcasts();
613 mPendingBroadcasts = 0;
614 }
615 }
616 }
617
Nick Pellye0fd6932012-07-11 10:26:13 -0700618 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700619 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
620 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400621 synchronized (this) {
622 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700623 }
624 }
625
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400626 // this must be called while synchronized by caller in a synchronized block
627 // containing the sending of the broadcaset
628 private void incrementPendingBroadcastsLocked() {
629 if (mPendingBroadcasts++ == 0) {
630 LocationManagerService.this.incrementPendingBroadcasts();
631 }
632 }
633
634 private void decrementPendingBroadcastsLocked() {
635 if (--mPendingBroadcasts == 0) {
636 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700637 }
638 }
639 }
640
Nick Pellye0fd6932012-07-11 10:26:13 -0700641 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700642 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400643 //Do not use getReceiver here as that will add the ILocationListener to
644 //the receiver list if it is not found. If it is not found then the
645 //LocationListener was removed when it had a pending broadcast and should
646 //not be added back.
647 IBinder binder = listener.asBinder();
648 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700649 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400650 synchronized (receiver) {
651 // so wakelock calls will succeed
652 long identity = Binder.clearCallingIdentity();
653 receiver.decrementPendingBroadcastsLocked();
654 Binder.restoreCallingIdentity(identity);
655 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 }
657 }
658
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700659 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400660 mProviders.add(provider);
661 mProvidersByName.put(provider.getName(), provider);
662 }
663
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700664 private void removeProviderLocked(LocationProviderInterface provider) {
665 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400666 mProviders.remove(provider);
667 mProvidersByName.remove(provider.getName());
668 }
669
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800670 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800671 * Returns "true" if access to the specified location provider is allowed by the current
672 * user's settings. Access to all location providers is forbidden to non-location-provider
673 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800674 *
675 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800676 * @return
677 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800678 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 if (mEnabledProviders.contains(provider)) {
680 return true;
681 }
682 if (mDisabledProviders.contains(provider)) {
683 return false;
684 }
685 // Use system settings
686 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687
Victoria Leaseb711d572012-10-02 13:14:11 -0700688 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 }
690
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700691 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800692 * Returns "true" if access to the specified location provider is allowed by the specified
693 * user's settings. Access to all location providers is forbidden to non-location-provider
694 * processes belonging to background users.
695 *
696 * @param provider the name of the location provider
697 * @param uid the requestor's UID
698 * @return
699 */
700 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
701 if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) {
702 return false;
703 }
704 return isAllowedByCurrentUserSettingsLocked(provider);
705 }
706
707 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700708 * Returns the permission string associated with the specified resolution level.
709 *
710 * @param resolutionLevel the resolution level
711 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700712 */
Victoria Lease37425c32012-10-16 16:08:48 -0700713 private String getResolutionPermission(int resolutionLevel) {
714 switch (resolutionLevel) {
715 case RESOLUTION_LEVEL_FINE:
716 return android.Manifest.permission.ACCESS_FINE_LOCATION;
717 case RESOLUTION_LEVEL_COARSE:
718 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
719 default:
720 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700722 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700723
Victoria Leaseda479c52012-10-15 15:24:16 -0700724 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700725 * Returns the resolution level allowed to the given PID/UID pair.
726 *
727 * @param pid the PID
728 * @param uid the UID
729 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700730 */
Victoria Lease37425c32012-10-16 16:08:48 -0700731 private int getAllowedResolutionLevel(int pid, int uid) {
732 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
733 pid, uid) == PackageManager.PERMISSION_GRANTED) {
734 return RESOLUTION_LEVEL_FINE;
735 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
736 pid, uid) == PackageManager.PERMISSION_GRANTED) {
737 return RESOLUTION_LEVEL_COARSE;
738 } else {
739 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700740 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700741 }
742
743 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700744 * Returns the resolution level allowed to the caller
745 *
746 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700747 */
Victoria Lease37425c32012-10-16 16:08:48 -0700748 private int getCallerAllowedResolutionLevel() {
749 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
750 }
751
752 /**
753 * Throw SecurityException if specified resolution level is insufficient to use geofences.
754 *
755 * @param allowedResolutionLevel resolution level allowed to caller
756 */
757 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
758 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700759 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
760 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 }
762
Victoria Lease37425c32012-10-16 16:08:48 -0700763 /**
764 * Return the minimum resolution level required to use the specified location provider.
765 *
766 * @param provider the name of the location provider
767 * @return minimum resolution level required for provider
768 */
769 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700770 if (LocationManager.GPS_PROVIDER.equals(provider) ||
771 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
772 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700773 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700774 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
775 LocationManager.FUSED_PROVIDER.equals(provider)) {
776 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700777 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700778 } else {
779 // mock providers
780 LocationProviderInterface lp = mMockProviders.get(provider);
781 if (lp != null) {
782 ProviderProperties properties = lp.getProperties();
783 if (properties != null) {
784 if (properties.mRequiresSatellite) {
785 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700786 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700787 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
788 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700789 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700790 }
791 }
792 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700793 }
Victoria Lease37425c32012-10-16 16:08:48 -0700794 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700795 }
796
Victoria Lease37425c32012-10-16 16:08:48 -0700797 /**
798 * Throw SecurityException if specified resolution level is insufficient to use the named
799 * location provider.
800 *
801 * @param allowedResolutionLevel resolution level allowed to caller
802 * @param providerName the name of the location provider
803 */
804 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
805 String providerName) {
806 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
807 if (allowedResolutionLevel < requiredResolutionLevel) {
808 switch (requiredResolutionLevel) {
809 case RESOLUTION_LEVEL_FINE:
810 throw new SecurityException("\"" + providerName + "\" location provider " +
811 "requires ACCESS_FINE_LOCATION permission.");
812 case RESOLUTION_LEVEL_COARSE:
813 throw new SecurityException("\"" + providerName + "\" location provider " +
814 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
815 default:
816 throw new SecurityException("Insufficient permission for \"" + providerName +
817 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700818 }
819 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700820 }
821
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800822 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800823 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
824 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800825 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800826 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800827 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800828 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800829 }
830 return -1;
831 }
832
833 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
834 int op = resolutionLevelToOp(allowedResolutionLevel);
835 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800836 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
837 return false;
838 }
839 }
840 return true;
841 }
842
843 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800844 int op = resolutionLevelToOp(allowedResolutionLevel);
845 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800846 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
847 return false;
848 }
849 }
850 return true;
851 }
852
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700853 /**
854 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700855 * fused, also including ones that are not permitted to
856 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700857 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700858 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700860 ArrayList<String> out;
861 synchronized (mLock) {
862 out = new ArrayList<String>(mProviders.size());
863 for (LocationProviderInterface provider : mProviders) {
864 String name = provider.getName();
865 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700866 continue;
867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 out.add(name);
869 }
870 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700871
872 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 return out;
874 }
875
Mike Lockwood03ca2162010-04-01 08:10:09 -0700876 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700877 * Return all providers by name, that match criteria and are optionally
878 * enabled.
879 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700880 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700881 @Override
882 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700883 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700884 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800885 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -0700886 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700887 try {
888 synchronized (mLock) {
889 out = new ArrayList<String>(mProviders.size());
890 for (LocationProviderInterface provider : mProviders) {
891 String name = provider.getName();
892 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700893 continue;
894 }
Victoria Lease37425c32012-10-16 16:08:48 -0700895 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -0800896 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700897 continue;
898 }
899 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
900 name, provider.getProperties(), criteria)) {
901 continue;
902 }
903 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700904 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700905 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700906 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700907 } finally {
908 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700909 }
910
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700911 if (D) Log.d(TAG, "getProviders()=" + out);
912 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700913 }
914
915 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700916 * Return the name of the best provider given a Criteria object.
917 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700918 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700919 * has been deprecated as well. So this method now uses
920 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700921 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700922 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700923 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700924 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700925
926 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700927 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700928 result = pickBest(providers);
929 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
930 return result;
931 }
932 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700933 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700934 result = pickBest(providers);
935 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
936 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700937 }
938
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700939 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700940 return null;
941 }
942
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700943 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700944 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700945 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700946 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
947 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700948 } else {
949 return providers.get(0);
950 }
951 }
952
Nick Pellye0fd6932012-07-11 10:26:13 -0700953 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700954 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
955 LocationProviderInterface p = mProvidersByName.get(provider);
956 if (p == null) {
957 throw new IllegalArgumentException("provider=" + provider);
958 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700959
960 boolean result = LocationProvider.propertiesMeetCriteria(
961 p.getName(), p.getProperties(), criteria);
962 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
963 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700964 }
965
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700967 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400968 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500969 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 boolean isEnabled = p.isEnabled();
971 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -0800972 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700974 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700975 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700977 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700978 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700980 }
981 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700982 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
983 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
985 }
986
Victoria Leaseb711d572012-10-02 13:14:11 -0700987 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 int listeners = 0;
989
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500990 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700991 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992
993 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700994
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
996 if (records != null) {
997 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700998 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -07001000 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001001 // Sends a notification message to the receiver
1002 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1003 if (deadReceivers == null) {
1004 deadReceivers = new ArrayList<Receiver>();
1005 }
1006 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001008 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
1011 }
1012
1013 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001014 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 removeUpdatesLocked(deadReceivers.get(i));
1016 }
1017 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 if (enabled) {
1020 p.enable();
1021 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001022 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
1024 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 }
1028
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001029 private void applyRequirementsLocked(String provider) {
1030 LocationProviderInterface p = mProvidersByName.get(provider);
1031 if (p == null) return;
1032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001034 WorkSource worksource = new WorkSource();
1035 ProviderRequest providerRequest = new ProviderRequest();
1036
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001038 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001039 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001040 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1041 record.mReceiver.mAllowedResolutionLevel)) {
1042 LocationRequest locationRequest = record.mRequest;
1043 providerRequest.locationRequests.add(locationRequest);
1044 if (locationRequest.getInterval() < providerRequest.interval) {
1045 providerRequest.reportLocation = true;
1046 providerRequest.interval = locationRequest.getInterval();
1047 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001048 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001049 }
1050 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001051
1052 if (providerRequest.reportLocation) {
1053 // calculate who to blame for power
1054 // This is somewhat arbitrary. We pick a threshold interval
1055 // that is slightly higher that the minimum interval, and
1056 // spread the blame across all applications with a request
1057 // under that threshold.
1058 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1059 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001060 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001061 LocationRequest locationRequest = record.mRequest;
1062 if (locationRequest.getInterval() <= thresholdInterval) {
Dianne Hackborn002a54e2013-01-10 17:34:55 -08001063 worksource.add(record.mReceiver.mUid, record.mReceiver.mPackageName);
Victoria Leaseb711d572012-10-02 13:14:11 -07001064 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001065 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 }
1068 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001069
1070 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1071 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 }
1073
1074 private class UpdateRecord {
1075 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001076 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001078 Location mLastFixBroadcast;
1079 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080
1081 /**
1082 * Note: must be constructed with lock held.
1083 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001084 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001086 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088
1089 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1090 if (records == null) {
1091 records = new ArrayList<UpdateRecord>();
1092 mRecordsByProvider.put(provider, records);
1093 }
1094 if (!records.contains(this)) {
1095 records.add(this);
1096 }
1097 }
1098
1099 /**
1100 * Method to be called when a record will no longer be used. Calling this multiple times
1101 * must have the same effect as calling it once.
1102 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001103 void disposeLocked(boolean removeReceiver) {
1104 // remove from mRecordsByProvider
1105 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1106 if (globalRecords != null) {
1107 globalRecords.remove(this);
1108 }
1109
1110 if (!removeReceiver) return; // the caller will handle the rest
1111
1112 // remove from Receiver#mUpdateRecords
1113 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1114 if (receiverRecords != null) {
1115 receiverRecords.remove(this.mProvider);
1116
1117 // and also remove the Receiver if it has no more update records
1118 if (removeReceiver && receiverRecords.size() == 0) {
1119 removeUpdatesLocked(mReceiver);
1120 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001121 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001122 }
1123
1124 @Override
1125 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001126 StringBuilder s = new StringBuilder();
1127 s.append("UpdateRecord[");
1128 s.append(mProvider);
1129 s.append(' ').append(mReceiver.mPackageName).append('(');
1130 s.append(mReceiver.mUid).append(')');
1131 s.append(' ').append(mRequest);
1132 s.append(']');
1133 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 }
1136
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001137 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001138 IBinder binder = listener.asBinder();
1139 Receiver receiver = mReceivers.get(binder);
1140 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001141 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001142 mReceivers.put(binder, receiver);
1143
1144 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001145 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001146 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001147 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001148 return null;
1149 }
1150 }
1151 return receiver;
1152 }
1153
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001154 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001155 Receiver receiver = mReceivers.get(intent);
1156 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001157 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001158 mReceivers.put(intent, receiver);
1159 }
1160 return receiver;
1161 }
1162
Victoria Lease37425c32012-10-16 16:08:48 -07001163 /**
1164 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1165 * and consistency requirements.
1166 *
1167 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001168 * @return a version of request that meets the given resolution and consistency requirements
1169 * @hide
1170 */
1171 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1172 LocationRequest sanitizedRequest = new LocationRequest(request);
1173 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1174 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001175 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001176 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001177 break;
1178 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001179 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001180 break;
1181 }
1182 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001183 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1184 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001185 }
Victoria Lease37425c32012-10-16 16:08:48 -07001186 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1187 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001188 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001189 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001190 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001191 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001192 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001193 }
Victoria Lease37425c32012-10-16 16:08:48 -07001194 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001195 }
1196
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001197 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001198 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001199 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001200 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001201 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001202 String[] packages = mPackageManager.getPackagesForUid(uid);
1203 if (packages == null) {
1204 throw new SecurityException("invalid UID " + uid);
1205 }
1206 for (String pkg : packages) {
1207 if (packageName.equals(pkg)) return;
1208 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001209 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001210 }
1211
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001212 private void checkPendingIntent(PendingIntent intent) {
1213 if (intent == null) {
1214 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001215 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001216 }
1217
1218 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1219 int pid, int uid, String packageName) {
1220 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001221 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 } else if (intent != null && listener != null) {
1223 throw new IllegalArgumentException("cannot register both listener and intent");
1224 } else if (intent != null) {
1225 checkPendingIntent(intent);
1226 return getReceiver(intent, pid, uid, packageName);
1227 } else {
1228 return getReceiver(listener, pid, uid, packageName);
1229 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001230 }
1231
Nick Pellye0fd6932012-07-11 10:26:13 -07001232 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001233 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1234 PendingIntent intent, String packageName) {
1235 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1236 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001237 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1238 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1239 request.getProvider());
1240 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001242 final int pid = Binder.getCallingPid();
1243 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001244 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001245 long identity = Binder.clearCallingIdentity();
1246 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001247 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1248 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001249 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001250 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1251
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001252 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001253 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001254 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 } finally {
1256 Binder.restoreCallingIdentity(identity);
1257 }
1258 }
1259
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001260 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1261 int pid, int uid, String packageName) {
1262 // Figure out the provider. Either its explicitly request (legacy use cases), or
1263 // use the fused provider
1264 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1265 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001266 if (name == null) {
1267 throw new IllegalArgumentException("provider name must not be null");
1268 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001269 LocationProviderInterface provider = mProvidersByName.get(name);
1270 if (provider == null) {
1271 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1272 }
1273
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001274 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1275 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001276
1277 UpdateRecord record = new UpdateRecord(name, request, receiver);
1278 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1279 if (oldRecord != null) {
1280 oldRecord.disposeLocked(false);
1281 }
1282
Victoria Lease09eeaec2013-02-05 11:34:13 -08001283 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 if (isProviderEnabled) {
1285 applyRequirementsLocked(name);
1286 } else {
1287 // Notify the listener that updates are currently disabled
1288 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 }
1290 }
1291
Nick Pellye0fd6932012-07-11 10:26:13 -07001292 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001293 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1294 String packageName) {
1295 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001296
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001297 final int pid = Binder.getCallingPid();
1298 final int uid = Binder.getCallingUid();
1299 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1300
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001301 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001302 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001304 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001305 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001307 } finally {
1308 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 }
1310 }
1311
1312 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001313 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001314
1315 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1316 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1317 synchronized (receiver) {
1318 if (receiver.mPendingBroadcasts > 0) {
1319 decrementPendingBroadcasts();
1320 receiver.mPendingBroadcasts = 0;
1321 }
1322 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 }
1324
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001325 // Record which providers were associated with this listener
1326 HashSet<String> providers = new HashSet<String>();
1327 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1328 if (oldRecords != null) {
1329 // Call dispose() on the obsolete update records.
1330 for (UpdateRecord record : oldRecords.values()) {
1331 record.disposeLocked(false);
1332 }
1333 // Accumulate providers
1334 providers.addAll(oldRecords.keySet());
1335 }
1336
1337 // update provider
1338 for (String provider : providers) {
1339 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001340 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001341 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 }
1343
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001344 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 }
1346 }
1347
Nick Pellye0fd6932012-07-11 10:26:13 -07001348 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001349 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001350 if (D) Log.d(TAG, "getLastLocation: " + request);
1351 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001352 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001353 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001354 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1355 request.getProvider());
1356 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001357
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001358 final int uid = Binder.getCallingUid();
1359 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001360 try {
1361 if (mBlacklist.isBlacklisted(packageName)) {
1362 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1363 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001364 return null;
1365 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001366
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001367 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1368 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1369 packageName);
1370 return null;
1371 }
1372
Victoria Leaseb711d572012-10-02 13:14:11 -07001373 synchronized (mLock) {
1374 // Figure out the provider. Either its explicitly request (deprecated API's),
1375 // or use the fused provider
1376 String name = request.getProvider();
1377 if (name == null) name = LocationManager.FUSED_PROVIDER;
1378 LocationProviderInterface provider = mProvidersByName.get(name);
1379 if (provider == null) return null;
1380
Victoria Lease09eeaec2013-02-05 11:34:13 -08001381 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001382
1383 Location location = mLastLocation.get(name);
1384 if (location == null) {
1385 return null;
1386 }
Victoria Lease37425c32012-10-16 16:08:48 -07001387 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001388 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1389 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001390 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001391 }
Victoria Lease37425c32012-10-16 16:08:48 -07001392 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001393 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001394 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001395 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001396 return null;
1397 } finally {
1398 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001399 }
1400 }
1401
1402 @Override
1403 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1404 String packageName) {
1405 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001406 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1407 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001408 checkPendingIntent(intent);
1409 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001410 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1411 request.getProvider());
1412 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001413
Victoria Lease37425c32012-10-16 16:08:48 -07001414 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001415
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001416 // geo-fence manager uses the public location API, need to clear identity
1417 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001418 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1419 // temporary measure until geofences work for secondary users
1420 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1421 return;
1422 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001423 long identity = Binder.clearCallingIdentity();
1424 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001425 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1426 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001427 } finally {
1428 Binder.restoreCallingIdentity(identity);
1429 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001430 }
1431
1432 @Override
1433 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001434 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001435 checkPendingIntent(intent);
1436 checkPackageName(packageName);
1437
1438 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1439
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001440 // geo-fence manager uses the public location API, need to clear identity
1441 long identity = Binder.clearCallingIdentity();
1442 try {
1443 mGeofenceManager.removeFence(geofence, intent);
1444 } finally {
1445 Binder.restoreCallingIdentity(identity);
1446 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001447 }
1448
1449
1450 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001451 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001452 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 return false;
1454 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001455 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1456 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001457 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001459 final int uid = Binder.getCallingUid();
1460 final long ident = Binder.clearCallingIdentity();
1461 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001462 if (checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001463 return false;
1464 }
1465 } finally {
1466 Binder.restoreCallingIdentity(ident);
1467 }
1468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001470 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001471 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001472 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001473 return false;
1474 }
1475 return true;
1476 }
1477
Nick Pellye0fd6932012-07-11 10:26:13 -07001478 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001480 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001481 try {
1482 mGpsStatusProvider.removeGpsStatusListener(listener);
1483 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001484 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 }
1487 }
1488
Nick Pellye0fd6932012-07-11 10:26:13 -07001489 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001491 if (provider == null) {
1492 // throw NullPointerException to remain compatible with previous implementation
1493 throw new NullPointerException();
1494 }
Victoria Lease37425c32012-10-16 16:08:48 -07001495 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1496 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001499 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 != PackageManager.PERMISSION_GRANTED)) {
1501 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1502 }
1503
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001504 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001505 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001506 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001507
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001508 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 }
1510 }
1511
Nick Pellye0fd6932012-07-11 10:26:13 -07001512 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001513 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001514 if (Binder.getCallingUid() != Process.myUid()) {
1515 throw new SecurityException(
1516 "calling sendNiResponse from outside of the system is not allowed");
1517 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001518 try {
1519 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001520 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001521 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001522 return false;
1523 }
1524 }
1525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001527 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001528 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 * accessed by the caller
1530 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001531 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001532 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001533 if (mProvidersByName.get(provider) == null) {
1534 return null;
1535 }
1536
Victoria Lease37425c32012-10-16 16:08:48 -07001537 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1538 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001540 LocationProviderInterface p;
1541 synchronized (mLock) {
1542 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 }
1544
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001545 if (p == null) return null;
1546 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 }
1548
Nick Pellye0fd6932012-07-11 10:26:13 -07001549 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001551 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1552 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001553 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1554
Victoria Lease09eeaec2013-02-05 11:34:13 -08001555 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001556 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001557 try {
1558 synchronized (mLock) {
1559 LocationProviderInterface p = mProvidersByName.get(provider);
1560 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001561
Victoria Lease09eeaec2013-02-05 11:34:13 -08001562 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001563 }
1564 } finally {
1565 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001566 }
1567 }
1568
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001569 /**
1570 * Returns "true" if the UID belongs to a bound location provider.
1571 *
1572 * @param uid the uid
1573 * @return true if uid belongs to a bound location provider
1574 */
1575 private boolean isUidALocationProvider(int uid) {
1576 if (uid == Process.SYSTEM_UID) {
1577 return true;
1578 }
1579 if (mGeocodeProvider != null) {
1580 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1581 }
1582 for (LocationProviderProxy proxy : mProxyProviders) {
1583 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
1584 }
1585 return false;
1586 }
1587
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001588 private void checkCallerIsProvider() {
1589 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1590 == PackageManager.PERMISSION_GRANTED) {
1591 return;
1592 }
1593
1594 // Previously we only used the INSTALL_LOCATION_PROVIDER
1595 // check. But that is system or signature
1596 // protection level which is not flexible enough for
1597 // providers installed oustide the system image. So
1598 // also allow providers with a UID matching the
1599 // currently bound package name
1600
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001601 if (isUidALocationProvider(Binder.getCallingUid())) {
1602 return;
1603 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001604
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001605 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1606 "or UID of a currently bound location provider");
1607 }
1608
1609 private boolean doesPackageHaveUid(int uid, String packageName) {
1610 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 return false;
1612 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001613 try {
1614 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1615 if (appInfo.uid != uid) {
1616 return false;
1617 }
1618 } catch (NameNotFoundException e) {
1619 return false;
1620 }
1621 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 }
1623
Nick Pellye0fd6932012-07-11 10:26:13 -07001624 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001625 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001626 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001627
Nick Pelly2eeeec22012-07-18 13:13:37 -07001628 if (!location.isComplete()) {
1629 Log.w(TAG, "Dropping incomplete location: " + location);
1630 return;
1631 }
1632
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001633 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1634 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001635 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001636 mLocationHandler.sendMessageAtFrontOfQueue(m);
1637 }
1638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639
Laurent Tu75defb62012-11-01 16:21:52 -07001640 private static boolean shouldBroadcastSafe(
1641 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 // Always broadcast the first update
1643 if (lastLoc == null) {
1644 return true;
1645 }
1646
Nick Pellyf1be6862012-05-15 10:53:42 -07001647 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001648 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001649 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001650 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 return false;
1652 }
1653
1654 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001655 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 if (minDistance > 0.0) {
1657 if (loc.distanceTo(lastLoc) <= minDistance) {
1658 return false;
1659 }
1660 }
1661
Laurent Tu75defb62012-11-01 16:21:52 -07001662 // Check whether sufficient number of udpates is left
1663 if (record.mRequest.getNumUpdates() <= 0) {
1664 return false;
1665 }
1666
1667 // Check whether the expiry date has passed
1668 if (record.mRequest.getExpireAt() < now) {
1669 return false;
1670 }
1671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 return true;
1673 }
1674
Mike Lockwooda4903f22010-02-17 06:42:23 -05001675 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001676 if (D) Log.d(TAG, "incoming location: " + location);
1677
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001678 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001679 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680
Laurent Tu60ec50a2012-10-04 17:00:10 -07001681 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001682 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001683 if (p == null) return;
1684
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001685 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001686 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1687 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001688 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001689 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001690 lastLocation = new Location(provider);
1691 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001692 } else {
1693 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1694 if (noGPSLocation == null && lastNoGPSLocation != null) {
1695 // New location has no no-GPS location: adopt last no-GPS location. This is set
1696 // directly into location because we do not want to notify COARSE clients.
1697 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1698 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001699 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001700 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701
Laurent Tu60ec50a2012-10-04 17:00:10 -07001702 // Skip if there are no UpdateRecords for this provider.
1703 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1704 if (records == null || records.size() == 0) return;
1705
Victoria Lease09016ab2012-09-16 12:33:15 -07001706 // Fetch coarse location
1707 Location coarseLocation = null;
1708 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1709 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1710 }
1711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 // Fetch latest status update time
1713 long newStatusUpdateTime = p.getStatusUpdateTime();
1714
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001715 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 Bundle extras = new Bundle();
1717 int status = p.getStatus(extras);
1718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001720 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001723 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001725 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001726
Victoria Lease269518e2012-10-29 08:25:39 -07001727 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1728 if (receiverUserId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001729 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001730 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001731 " (current user: " + mCurrentUserId + ", app: " +
1732 receiver.mPackageName + ")");
1733 }
1734 continue;
1735 }
1736
Nick Pelly4035f5a2012-08-17 14:43:49 -07001737 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1738 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1739 receiver.mPackageName);
1740 continue;
1741 }
1742
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001743 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
1744 receiver.mAllowedResolutionLevel)) {
1745 if (D) Log.d(TAG, "skipping loc update for no op app: " +
1746 receiver.mPackageName);
1747 continue;
1748 }
1749
Victoria Lease09016ab2012-09-16 12:33:15 -07001750 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001751 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1752 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001753 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001754 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001755 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001756 if (notifyLocation != null) {
1757 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001758 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001759 if (lastLoc == null) {
1760 lastLoc = new Location(notifyLocation);
1761 r.mLastFixBroadcast = lastLoc;
1762 } else {
1763 lastLoc.set(notifyLocation);
1764 }
1765 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1766 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1767 receiverDead = true;
1768 }
Laurent Tu75defb62012-11-01 16:21:52 -07001769 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 }
1771 }
1772
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001773 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001775 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001777 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001779 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001780 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001781 }
1782 }
1783
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001784 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001785 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001786 if (deadUpdateRecords == null) {
1787 deadUpdateRecords = new ArrayList<UpdateRecord>();
1788 }
1789 deadUpdateRecords.add(r);
1790 }
1791 // track dead receivers
1792 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001793 if (deadReceivers == null) {
1794 deadReceivers = new ArrayList<Receiver>();
1795 }
1796 if (!deadReceivers.contains(receiver)) {
1797 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 }
1799 }
1800 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001801
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001802 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001804 for (Receiver receiver : deadReceivers) {
1805 removeUpdatesLocked(receiver);
1806 }
1807 }
1808 if (deadUpdateRecords != null) {
1809 for (UpdateRecord r : deadUpdateRecords) {
1810 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 }
Victoria Lease8b38b292012-12-04 15:04:43 -08001812 applyRequirementsLocked(provider);
1813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 }
1815
1816 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001817 public LocationWorkerHandler(Looper looper) {
1818 super(looper, null, true);
1819 }
1820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 @Override
1822 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001823 switch (msg.what) {
1824 case MSG_LOCATION_CHANGED:
1825 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1826 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001827 }
1828 }
1829 }
1830
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001831 private boolean isMockProvider(String provider) {
1832 synchronized (mLock) {
1833 return mMockProviders.containsKey(provider);
1834 }
1835 }
1836
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001837 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001838 // create a working copy of the incoming Location so that the service can modify it without
1839 // disturbing the caller's copy
1840 Location myLocation = new Location(location);
1841 String provider = myLocation.getProvider();
1842
1843 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
1844 // bit if location did not come from a mock provider because passive/fused providers can
1845 // forward locations from mock providers, and should not grant them legitimacy in doing so.
1846 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
1847 myLocation.setIsFromMockProvider(true);
1848 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08001849
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001850 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001851 if (isAllowedByCurrentUserSettingsLocked(provider)) {
1852 if (!passive) {
1853 // notify passive provider of the new location
1854 mPassiveProvider.updateLocation(myLocation);
1855 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001856 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001859 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860
Mike Lockwoode97ae402010-09-29 15:23:46 -04001861 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1862 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001863 public void onPackageDisappeared(String packageName, int reason) {
1864 // remove all receivers associated with this package name
1865 synchronized (mLock) {
1866 ArrayList<Receiver> deadReceivers = null;
1867
1868 for (Receiver receiver : mReceivers.values()) {
1869 if (receiver.mPackageName.equals(packageName)) {
1870 if (deadReceivers == null) {
1871 deadReceivers = new ArrayList<Receiver>();
1872 }
1873 deadReceivers.add(receiver);
1874 }
1875 }
1876
1877 // perform removal outside of mReceivers loop
1878 if (deadReceivers != null) {
1879 for (Receiver receiver : deadReceivers) {
1880 removeUpdatesLocked(receiver);
1881 }
1882 }
1883 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001884 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001885 };
1886
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 // Wake locks
1888
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001889 private void incrementPendingBroadcasts() {
1890 synchronized (mWakeLock) {
1891 if (mPendingBroadcasts++ == 0) {
1892 try {
1893 mWakeLock.acquire();
1894 log("Acquired wakelock");
1895 } catch (Exception e) {
1896 // This is to catch a runtime exception thrown when we try to release an
1897 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001898 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001899 }
1900 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001901 }
1902 }
1903
1904 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001905 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001906 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001907 try {
1908 // Release wake lock
1909 if (mWakeLock.isHeld()) {
1910 mWakeLock.release();
1911 log("Released wakelock");
1912 } else {
1913 log("Can't release wakelock again!");
1914 }
1915 } catch (Exception e) {
1916 // This is to catch a runtime exception thrown when we try to release an
1917 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001918 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001919 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001920 }
1921 }
1922 }
1923
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 // Geocoder
1925
Nick Pellye0fd6932012-07-11 10:26:13 -07001926 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001927 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001928 return mGeocodeProvider != null;
1929 }
1930
Nick Pellye0fd6932012-07-11 10:26:13 -07001931 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001932 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001933 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001934 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001935 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1936 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001938 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001939 }
1940
Mike Lockwooda55c3212009-04-15 11:10:11 -04001941
Nick Pellye0fd6932012-07-11 10:26:13 -07001942 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001944 double lowerLeftLatitude, double lowerLeftLongitude,
1945 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001946 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001947
1948 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001949 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1950 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1951 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001953 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 }
1955
1956 // Mock Providers
1957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958 private void checkMockPermissionsSafe() {
1959 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1960 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1961 if (!allowMocks) {
1962 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1963 }
1964
1965 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1966 PackageManager.PERMISSION_GRANTED) {
1967 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 }
1970
Nick Pellye0fd6932012-07-11 10:26:13 -07001971 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001972 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 checkMockPermissionsSafe();
1974
Mike Lockwooda4903f22010-02-17 06:42:23 -05001975 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1976 throw new IllegalArgumentException("Cannot mock the passive location provider");
1977 }
1978
Mike Lockwood86328a92009-10-23 08:38:25 -04001979 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001980 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001981 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001982 // remove the real provider if we are replacing GPS or network provider
1983 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001984 || LocationManager.NETWORK_PROVIDER.equals(name)
1985 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001986 LocationProviderInterface p = mProvidersByName.get(name);
1987 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001988 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001989 }
1990 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001991 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1993 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001994 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001995 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001996 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 updateProvidersLocked();
1998 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001999 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
2001
Nick Pellye0fd6932012-07-11 10:26:13 -07002002 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002003 public void removeTestProvider(String provider) {
2004 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002005 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09002006 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002007 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2009 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002010 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002011 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002012
2013 // reinstate real provider if available
2014 LocationProviderInterface realProvider = mRealProviders.get(provider);
2015 if (realProvider != null) {
2016 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002017 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002018 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002020 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 }
2022 }
2023
Nick Pellye0fd6932012-07-11 10:26:13 -07002024 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 public void setTestProviderLocation(String provider, Location loc) {
2026 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002027 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002028 MockProvider mockProvider = mMockProviders.get(provider);
2029 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2031 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002032 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2033 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002034 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002035 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 }
2037 }
2038
Nick Pellye0fd6932012-07-11 10:26:13 -07002039 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 public void clearTestProviderLocation(String provider) {
2041 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002042 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002043 MockProvider mockProvider = mMockProviders.get(provider);
2044 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2046 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002047 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 }
2049 }
2050
Nick Pellye0fd6932012-07-11 10:26:13 -07002051 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 public void setTestProviderEnabled(String provider, boolean enabled) {
2053 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002054 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002055 MockProvider mockProvider = mMockProviders.get(provider);
2056 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002057 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2058 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002059 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002061 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002062 mEnabledProviders.add(provider);
2063 mDisabledProviders.remove(provider);
2064 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002065 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 mEnabledProviders.remove(provider);
2067 mDisabledProviders.add(provider);
2068 }
2069 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002070 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002071 }
2072 }
2073
Nick Pellye0fd6932012-07-11 10:26:13 -07002074 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002075 public void clearTestProviderEnabled(String provider) {
2076 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002077 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002078 MockProvider mockProvider = mMockProviders.get(provider);
2079 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002080 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2081 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002082 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 mEnabledProviders.remove(provider);
2084 mDisabledProviders.remove(provider);
2085 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002086 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 }
2088 }
2089
Nick Pellye0fd6932012-07-11 10:26:13 -07002090 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002091 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2092 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002093 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002094 MockProvider mockProvider = mMockProviders.get(provider);
2095 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002096 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2097 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002098 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002099 }
2100 }
2101
Nick Pellye0fd6932012-07-11 10:26:13 -07002102 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002103 public void clearTestProviderStatus(String provider) {
2104 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002105 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002106 MockProvider mockProvider = mMockProviders.get(provider);
2107 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2109 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002110 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002111 }
2112 }
2113
2114 private void log(String log) {
2115 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002116 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 }
2118 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002119
2120 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002121 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2122 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2123 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002124 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002125 + Binder.getCallingPid()
2126 + ", uid=" + Binder.getCallingUid());
2127 return;
2128 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002129
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002130 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002131 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002133 for (Receiver receiver : mReceivers.values()) {
2134 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002136 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002137 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2138 pw.println(" " + entry.getKey() + ":");
2139 for (UpdateRecord record : entry.getValue()) {
2140 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002141 }
2142 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002143 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002144 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2145 String provider = entry.getKey();
2146 Location location = entry.getValue();
2147 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002148 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002149
Nick Pellye0fd6932012-07-11 10:26:13 -07002150 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 if (mEnabledProviders.size() > 0) {
2153 pw.println(" Enabled Providers:");
2154 for (String i : mEnabledProviders) {
2155 pw.println(" " + i);
2156 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002158 }
2159 if (mDisabledProviders.size() > 0) {
2160 pw.println(" Disabled Providers:");
2161 for (String i : mDisabledProviders) {
2162 pw.println(" " + i);
2163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002165 pw.append(" ");
2166 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 if (mMockProviders.size() > 0) {
2168 pw.println(" Mock Providers:");
2169 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002170 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 }
2172 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002173
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002174 pw.append(" fudger: ");
2175 mLocationFudger.dump(fd, pw, args);
2176
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002177 if (args.length > 0 && "short".equals(args[0])) {
2178 return;
2179 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002180 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002181 pw.print(provider.getName() + " Internal State");
2182 if (provider instanceof LocationProviderProxy) {
2183 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2184 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002185 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002186 pw.println(":");
2187 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002189 }
2190 }
2191}