blob: eb833eb54de532b8a5e0d2bd33e5e0b94669432a [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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070020import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070024import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050026import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070028import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050029import android.content.pm.ResolveInfo;
30import android.content.pm.Signature;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050031import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070032import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070034import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050035import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070036import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040038import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.ILocationListener;
40import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040041import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.location.Location;
43import android.location.LocationManager;
44import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070045import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.Binder;
47import android.os.Bundle;
48import android.os.Handler;
49import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070050import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.Message;
52import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070053import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070055import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070056import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070057import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080060import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
Mike Lockwoode97ae402010-09-29 15:23:46 -040062import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070063import com.android.internal.location.ProviderProperties;
64import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040065import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070066import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040067import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070068import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070069import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040070import com.android.server.location.LocationProviderInterface;
71import com.android.server.location.LocationProviderProxy;
72import com.android.server.location.MockProvider;
73import com.android.server.location.PassiveProvider;
74
75import java.io.FileDescriptor;
76import java.io.PrintWriter;
77import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070078import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040079import java.util.HashMap;
80import java.util.HashSet;
81import java.util.List;
82import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040083import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
85/**
86 * The service class that manages LocationProviders and issues location
87 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 */
Brian Muramatsubb95cb92012-08-29 10:43:21 -070089public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070091 public static final boolean D = false;
92
93 private static final String WAKELOCK_KEY = TAG;
94 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
Victoria Lease37425c32012-10-16 16:08:48 -070096 // Location resolution level: no location data whatsoever
97 private static final int RESOLUTION_LEVEL_NONE = 0;
98 // Location resolution level: coarse location data only
99 private static final int RESOLUTION_LEVEL_COARSE = 1;
100 // Location resolution level: fine location data
101 private static final int RESOLUTION_LEVEL_FINE = 2;
102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700104 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700106 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400107 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700108 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
109
110 private static final String NETWORK_LOCATION_SERVICE_ACTION =
111 "com.android.location.service.v2.NetworkLocationProvider";
112 private static final String FUSED_LOCATION_SERVICE_ACTION =
113 "com.android.location.service.FusedLocationProvider";
114
115 private static final int MSG_LOCATION_CHANGED = 1;
116
Nick Pellyf1be6862012-05-15 10:53:42 -0700117 // Location Providers may sometimes deliver location updates
118 // slightly faster that requested - provide grace period so
119 // we don't unnecessarily filter events that are otherwise on
120 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700121 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700122
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700123 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
124
125 private final Context mContext;
126
127 // used internally for synchronization
128 private final Object mLock = new Object();
129
130 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700131 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700132 private GeofenceManager mGeofenceManager;
133 private PowerManager.WakeLock mWakeLock;
134 private PackageManager mPackageManager;
135 private GeocoderProxy mGeocodeProvider;
136 private IGpsStatusProvider mGpsStatusProvider;
137 private INetInitiatedListener mNetInitiatedListener;
138 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700139 private PassiveProvider mPassiveProvider; // track passive provider for special cases
140 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700141
142 // --- fields below are protected by mWakeLock ---
143 private int mPendingBroadcasts;
144
145 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 // Set of providers that are explicitly enabled
147 private final Set<String> mEnabledProviders = new HashSet<String>();
148
149 // Set of providers that are explicitly disabled
150 private final Set<String> mDisabledProviders = new HashSet<String>();
151
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700152 // Mock (test) providers
153 private final HashMap<String, MockProvider> mMockProviders =
154 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700156 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400157 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700159 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500160 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700161 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400162
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700163 // real providers, saved here when mocked out
164 private final HashMap<String, LocationProviderInterface> mRealProviders =
165 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 // mapping from provider name to provider
168 private final HashMap<String, LocationProviderInterface> mProvidersByName =
169 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700171 // mapping from provider name to all its UpdateRecords
172 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
173 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700174
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700175 // mapping from provider name to last known location
176 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700178 // all providers that operate over proxy, for authorizing incoming location
179 private final ArrayList<LocationProviderProxy> mProxyProviders =
180 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181
Victoria Lease38389b62012-09-30 11:44:22 -0700182 // current active user on the device - other users are denied location data
183 private int mCurrentUserId = UserHandle.USER_OWNER;
184
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 public LocationManagerService(Context context) {
186 super();
187 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800188
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700189 if (D) Log.d(TAG, "Constructed");
190
191 // most startup is deferred until systemReady()
192 }
193
194 public void systemReady() {
195 Thread thread = new Thread(null, this, THREAD_NAME);
196 thread.start();
197 }
198
199 @Override
200 public void run() {
201 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
202 Looper.prepare();
203 mLocationHandler = new LocationWorkerHandler();
204 init();
205 Looper.loop();
206 }
207
208 private void init() {
209 if (D) Log.d(TAG, "init()");
210
211 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
212 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
213 mPackageManager = mContext.getPackageManager();
214
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700215 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
216 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700217 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700218
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700219 synchronized (mLock) {
220 loadProvidersLocked();
221 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700222
Nick Pelly4035f5a2012-08-17 14:43:49 -0700223 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700224
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700225 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700226 mContext.getContentResolver().registerContentObserver(
227 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
228 new ContentObserver(mLocationHandler) {
229 @Override
230 public void onChange(boolean selfChange) {
231 synchronized (mLock) {
232 updateProvidersLocked();
233 }
234 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700235 }, UserHandle.USER_ALL);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700236 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700237
Victoria Lease38389b62012-09-30 11:44:22 -0700238 // listen for user change
239 IntentFilter intentFilter = new IntentFilter();
240 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
241
242 mContext.registerReceiverAsUser(new BroadcastReceiver() {
243 @Override
244 public void onReceive(Context context, Intent intent) {
245 String action = intent.getAction();
246 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
247 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
248 }
249 }
250 }, UserHandle.ALL, intentFilter, null, null);
251
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700252 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700253 }
254
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500255 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
256 PackageManager pm = mContext.getPackageManager();
257 String systemPackageName = mContext.getPackageName();
258 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
259
260 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
261 new Intent(FUSED_LOCATION_SERVICE_ACTION),
262 PackageManager.GET_META_DATA, mCurrentUserId);
263 for (ResolveInfo rInfo : rInfos) {
264 String packageName = rInfo.serviceInfo.packageName;
265
266 // Check that the signature is in the list of supported sigs. If it's not in
267 // this list the standard provider binding logic won't bind to it.
268 try {
269 PackageInfo pInfo;
270 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
271 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
272 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
273 ", but has wrong signature, ignoring");
274 continue;
275 }
276 } catch (NameNotFoundException e) {
277 Log.e(TAG, "missing package: " + packageName);
278 continue;
279 }
280
281 // Get the version info
282 if (rInfo.serviceInfo.metaData == null) {
283 Log.w(TAG, "Found fused provider without metadata: " + packageName);
284 continue;
285 }
286
287 int version = rInfo.serviceInfo.metaData.getInt(
288 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
289 if (version == 0) {
290 // This should be the fallback fused location provider.
291
292 // Make sure it's in the system partition.
293 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
294 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
295 continue;
296 }
297
298 // Check that the fallback is signed the same as the OS
299 // as a proxy for coreApp="true"
300 if (pm.checkSignatures(systemPackageName, packageName)
301 != PackageManager.SIGNATURE_MATCH) {
302 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
303 + packageName);
304 continue;
305 }
306
307 // Found a valid fallback.
308 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
309 return;
310 } else {
311 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
312 }
313 }
314
315 throw new IllegalStateException("Unable to find a fused location provider that is in the "
316 + "system partition with version 0 and signed with the platform certificate. "
317 + "Such a package is needed to provide a default fused location provider in the "
318 + "event that no other fused location provider has been installed or is currently "
319 + "available. For example, coreOnly boot mode when decrypting the data "
320 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
321 }
322
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700323 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700324 // create a passive location provider, which is always enabled
325 PassiveProvider passiveProvider = new PassiveProvider(this);
326 addProviderLocked(passiveProvider);
327 mEnabledProviders.add(passiveProvider.getName());
328 mPassiveProvider = passiveProvider;
329
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700330 if (GpsLocationProvider.isSupported()) {
331 // Create a gps location provider
332 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
333 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
334 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
335 addProviderLocked(gpsProvider);
336 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
337 }
338
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700339 /*
340 Load package name(s) containing location provider support.
341 These packages can contain services implementing location providers:
342 Geocoder Provider, Network Location Provider, and
343 Fused Location Provider. They will each be searched for
344 service components implementing these providers.
345 The location framework also has support for installation
346 of new location providers at run-time. The new package does not
347 have to be explicitly listed here, however it must have a signature
348 that matches the signature of at least one package on this list.
349 */
350 Resources resources = mContext.getResources();
351 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500352 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700353 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500354 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
355 Arrays.toString(pkgs));
356 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
357
358 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700359
360 // bind to network provider
361 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
362 mContext,
363 LocationManager.NETWORK_PROVIDER,
364 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700365 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700366 if (networkProvider != null) {
367 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
368 mProxyProviders.add(networkProvider);
369 addProviderLocked(networkProvider);
370 } else {
371 Slog.w(TAG, "no network location provider found");
372 }
373
374 // bind to fused provider
375 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
376 mContext,
377 LocationManager.FUSED_PROVIDER,
378 FUSED_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700379 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700380 if (fusedLocationProvider != null) {
381 addProviderLocked(fusedLocationProvider);
382 mProxyProviders.add(fusedLocationProvider);
383 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700384 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700385 } else {
386 Slog.e(TAG, "no fused location provider found",
387 new IllegalStateException("Location service needs a fused location provider"));
388 }
389
390 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700391 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
392 mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700393 if (mGeocodeProvider == null) {
394 Slog.e(TAG, "no geocoder provider found");
395 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700396 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700399 * Called when the device's active user changes.
400 * @param userId the new active user's UserId
401 */
402 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700403 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700404 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700405 mLastLocation.clear();
406 for (LocationProviderInterface p : mProviders) {
407 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Leasee5601ce2012-10-26 14:34:48 -0700408 if (!LocationManager.FUSED_PROVIDER.equals(p.getName())) {
409 p.switchUser(userId);
410 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700411 }
Victoria Lease38389b62012-09-30 11:44:22 -0700412 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700413 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700414 }
415 }
416
417 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
419 * location updates.
420 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700421 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700422 final int mUid; // uid of receiver
423 final int mPid; // pid of receiver
424 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700425 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 final ILocationListener mListener;
428 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700430
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400431 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700432
Mike Lockwood48f17512009-04-23 09:12:08 -0700433 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700435 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
436 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700439 if (listener != null) {
440 mKey = listener.asBinder();
441 } else {
442 mKey = intent;
443 }
Victoria Lease37425c32012-10-16 16:08:48 -0700444 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700445 mUid = uid;
446 mPid = pid;
447 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 }
449
450 @Override
451 public boolean equals(Object otherObj) {
452 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700453 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 }
455 return false;
456 }
457
458 @Override
459 public int hashCode() {
460 return mKey.hashCode();
461 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 @Override
464 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700465 StringBuilder s = new StringBuilder();
466 s.append("Reciever[");
467 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700469 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700471 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700473 for (String p : mUpdateRecords.keySet()) {
474 s.append(" ").append(mUpdateRecords.get(p).toString());
475 }
476 s.append("]");
477 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 }
479
480 public boolean isListener() {
481 return mListener != null;
482 }
483
484 public boolean isPendingIntent() {
485 return mPendingIntent != null;
486 }
487
488 public ILocationListener getListener() {
489 if (mListener != null) {
490 return mListener;
491 }
492 throw new IllegalStateException("Request for non-existent listener");
493 }
494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
496 if (mListener != null) {
497 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700498 synchronized (this) {
499 // synchronize to ensure incrementPendingBroadcastsLocked()
500 // is called before decrementPendingBroadcasts()
501 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700502 // call this after broadcasting so we do not increment
503 // if we throw an exeption.
504 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 } catch (RemoteException e) {
507 return false;
508 }
509 } else {
510 Intent statusChanged = new Intent();
511 statusChanged.putExtras(extras);
512 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
513 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700514 synchronized (this) {
515 // synchronize to ensure incrementPendingBroadcastsLocked()
516 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700517 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700518 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700519 // call this after broadcasting so we do not increment
520 // if we throw an exeption.
521 incrementPendingBroadcastsLocked();
522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 } catch (PendingIntent.CanceledException e) {
524 return false;
525 }
526 }
527 return true;
528 }
529
530 public boolean callLocationChangedLocked(Location location) {
531 if (mListener != null) {
532 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700533 synchronized (this) {
534 // synchronize to ensure incrementPendingBroadcastsLocked()
535 // is called before decrementPendingBroadcasts()
536 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700537 // call this after broadcasting so we do not increment
538 // if we throw an exeption.
539 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 } catch (RemoteException e) {
542 return false;
543 }
544 } else {
545 Intent locationChanged = new Intent();
546 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
547 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700548 synchronized (this) {
549 // synchronize to ensure incrementPendingBroadcastsLocked()
550 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700551 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700552 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700553 // call this after broadcasting so we do not increment
554 // if we throw an exeption.
555 incrementPendingBroadcastsLocked();
556 }
557 } catch (PendingIntent.CanceledException e) {
558 return false;
559 }
560 }
561 return true;
562 }
563
564 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
565 if (mListener != null) {
566 try {
567 synchronized (this) {
568 // synchronize to ensure incrementPendingBroadcastsLocked()
569 // is called before decrementPendingBroadcasts()
570 if (enabled) {
571 mListener.onProviderEnabled(provider);
572 } else {
573 mListener.onProviderDisabled(provider);
574 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700575 // call this after broadcasting so we do not increment
576 // if we throw an exeption.
577 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700578 }
579 } catch (RemoteException e) {
580 return false;
581 }
582 } else {
583 Intent providerIntent = new Intent();
584 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
585 try {
586 synchronized (this) {
587 // synchronize to ensure incrementPendingBroadcastsLocked()
588 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700589 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700590 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700591 // call this after broadcasting so we do not increment
592 // if we throw an exeption.
593 incrementPendingBroadcastsLocked();
594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 } catch (PendingIntent.CanceledException e) {
596 return false;
597 }
598 }
599 return true;
600 }
601
Nick Pellyf1be6862012-05-15 10:53:42 -0700602 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700604 if (D) Log.d(TAG, "Location listener died");
605
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400606 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 removeUpdatesLocked(this);
608 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700609 synchronized (this) {
610 if (mPendingBroadcasts > 0) {
611 LocationManagerService.this.decrementPendingBroadcasts();
612 mPendingBroadcasts = 0;
613 }
614 }
615 }
616
Nick Pellye0fd6932012-07-11 10:26:13 -0700617 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700618 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
619 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400620 synchronized (this) {
621 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700622 }
623 }
624
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400625 // this must be called while synchronized by caller in a synchronized block
626 // containing the sending of the broadcaset
627 private void incrementPendingBroadcastsLocked() {
628 if (mPendingBroadcasts++ == 0) {
629 LocationManagerService.this.incrementPendingBroadcasts();
630 }
631 }
632
633 private void decrementPendingBroadcastsLocked() {
634 if (--mPendingBroadcasts == 0) {
635 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700636 }
637 }
638 }
639
Nick Pellye0fd6932012-07-11 10:26:13 -0700640 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700641 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400642 //Do not use getReceiver here as that will add the ILocationListener to
643 //the receiver list if it is not found. If it is not found then the
644 //LocationListener was removed when it had a pending broadcast and should
645 //not be added back.
646 IBinder binder = listener.asBinder();
647 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700648 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400649 synchronized (receiver) {
650 // so wakelock calls will succeed
651 long identity = Binder.clearCallingIdentity();
652 receiver.decrementPendingBroadcastsLocked();
653 Binder.restoreCallingIdentity(identity);
654 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 }
656 }
657
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700658 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400659 mProviders.add(provider);
660 mProvidersByName.put(provider.getName(), provider);
661 }
662
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700663 private void removeProviderLocked(LocationProviderInterface provider) {
664 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400665 mProviders.remove(provider);
666 mProvidersByName.remove(provider.getName());
667 }
668
Victoria Leasee5601ce2012-10-26 14:34:48 -0700669 /**
670 * Returns true if the specified UID is SYSTEM_UID or matches the current user.
671 *
672 * @param uid the uid
673 * @return true if uid is SYSTEM_UID or matches the current user
674 */
675 private boolean isCurrentUserOrSystemLocked(int uid) {
676 return uid == Process.SYSTEM_UID || UserHandle.getUserId(uid) == mCurrentUserId;
677 }
Mike Lockwood3d12b512009-04-21 23:25:35 -0700678
Victoria Leasee5601ce2012-10-26 14:34:48 -0700679 /**
680 * Returns the first UID in the current user's range.
681 *
682 * @return the first UID in the current user's range
683 */
684 private int getCurrentUidBaseLocked() {
685 return UserHandle.getUid(mCurrentUserId, 0);
686 }
687
688 private boolean isAllowedBySettingsLocked(String provider, int uid) {
689 if (!isCurrentUserOrSystemLocked(uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700690 return false;
691 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 if (mEnabledProviders.contains(provider)) {
693 return true;
694 }
695 if (mDisabledProviders.contains(provider)) {
696 return false;
697 }
Victoria Leasee5601ce2012-10-26 14:34:48 -0700698 if (uid == Process.SYSTEM_UID) {
699 return true;
700 }
701
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 // Use system settings
703 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704
Victoria Leaseb711d572012-10-02 13:14:11 -0700705 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 }
707
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700708 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700709 * Returns the permission string associated with the specified resolution level.
710 *
711 * @param resolutionLevel the resolution level
712 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700713 */
Victoria Lease37425c32012-10-16 16:08:48 -0700714 private String getResolutionPermission(int resolutionLevel) {
715 switch (resolutionLevel) {
716 case RESOLUTION_LEVEL_FINE:
717 return android.Manifest.permission.ACCESS_FINE_LOCATION;
718 case RESOLUTION_LEVEL_COARSE:
719 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
720 default:
721 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700723 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700724
Victoria Leaseda479c52012-10-15 15:24:16 -0700725 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700726 * Returns the resolution level allowed to the given PID/UID pair.
727 *
728 * @param pid the PID
729 * @param uid the UID
730 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700731 */
Victoria Lease37425c32012-10-16 16:08:48 -0700732 private int getAllowedResolutionLevel(int pid, int uid) {
733 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
734 pid, uid) == PackageManager.PERMISSION_GRANTED) {
735 return RESOLUTION_LEVEL_FINE;
736 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
737 pid, uid) == PackageManager.PERMISSION_GRANTED) {
738 return RESOLUTION_LEVEL_COARSE;
739 } else {
740 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700741 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700742 }
743
744 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700745 * Returns the resolution level allowed to the caller
746 *
747 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700748 */
Victoria Lease37425c32012-10-16 16:08:48 -0700749 private int getCallerAllowedResolutionLevel() {
750 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
751 }
752
753 /**
754 * Throw SecurityException if specified resolution level is insufficient to use geofences.
755 *
756 * @param allowedResolutionLevel resolution level allowed to caller
757 */
758 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
759 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700760 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
761 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 }
763
Victoria Lease37425c32012-10-16 16:08:48 -0700764 /**
765 * Return the minimum resolution level required to use the specified location provider.
766 *
767 * @param provider the name of the location provider
768 * @return minimum resolution level required for provider
769 */
770 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700771 if (LocationManager.GPS_PROVIDER.equals(provider) ||
772 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
773 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700774 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700775 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
776 LocationManager.FUSED_PROVIDER.equals(provider)) {
777 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700778 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700779 } else {
780 // mock providers
781 LocationProviderInterface lp = mMockProviders.get(provider);
782 if (lp != null) {
783 ProviderProperties properties = lp.getProperties();
784 if (properties != null) {
785 if (properties.mRequiresSatellite) {
786 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700787 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700788 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
789 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700790 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700791 }
792 }
793 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700794 }
Victoria Lease37425c32012-10-16 16:08:48 -0700795 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700796 }
797
Victoria Lease37425c32012-10-16 16:08:48 -0700798 /**
799 * Throw SecurityException if specified resolution level is insufficient to use the named
800 * location provider.
801 *
802 * @param allowedResolutionLevel resolution level allowed to caller
803 * @param providerName the name of the location provider
804 */
805 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
806 String providerName) {
807 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
808 if (allowedResolutionLevel < requiredResolutionLevel) {
809 switch (requiredResolutionLevel) {
810 case RESOLUTION_LEVEL_FINE:
811 throw new SecurityException("\"" + providerName + "\" location provider " +
812 "requires ACCESS_FINE_LOCATION permission.");
813 case RESOLUTION_LEVEL_COARSE:
814 throw new SecurityException("\"" + providerName + "\" location provider " +
815 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
816 default:
817 throw new SecurityException("Insufficient permission for \"" + providerName +
818 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700819 }
820 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700821 }
822
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700823 /**
824 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700825 * fused, also including ones that are not permitted to
826 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700827 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700828 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700830 ArrayList<String> out;
831 synchronized (mLock) {
832 out = new ArrayList<String>(mProviders.size());
833 for (LocationProviderInterface provider : mProviders) {
834 String name = provider.getName();
835 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700836 continue;
837 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 out.add(name);
839 }
840 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700841
842 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 return out;
844 }
845
Mike Lockwood03ca2162010-04-01 08:10:09 -0700846 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700847 * Return all providers by name, that match criteria and are optionally
848 * enabled.
849 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700850 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700851 @Override
852 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700853 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700854 ArrayList<String> out;
Victoria Leasee5601ce2012-10-26 14:34:48 -0700855 final int callingUid = Binder.getCallingUid();
856 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700857 try {
858 synchronized (mLock) {
859 out = new ArrayList<String>(mProviders.size());
860 for (LocationProviderInterface provider : mProviders) {
861 String name = provider.getName();
862 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700863 continue;
864 }
Victoria Lease37425c32012-10-16 16:08:48 -0700865 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Leasee5601ce2012-10-26 14:34:48 -0700866 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700867 continue;
868 }
869 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
870 name, provider.getProperties(), criteria)) {
871 continue;
872 }
873 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700874 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700875 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700876 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700877 } finally {
878 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700879 }
880
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700881 if (D) Log.d(TAG, "getProviders()=" + out);
882 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700883 }
884
885 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700886 * Return the name of the best provider given a Criteria object.
887 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700888 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700889 * has been deprecated as well. So this method now uses
890 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700891 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700892 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700893 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700894 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700895
896 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700897 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700898 result = pickBest(providers);
899 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
900 return result;
901 }
902 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700903 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700904 result = pickBest(providers);
905 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
906 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700907 }
908
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700909 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700910 return null;
911 }
912
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700913 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700914 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700915 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700916 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
917 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700918 } else {
919 return providers.get(0);
920 }
921 }
922
Nick Pellye0fd6932012-07-11 10:26:13 -0700923 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700924 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
925 LocationProviderInterface p = mProvidersByName.get(provider);
926 if (p == null) {
927 throw new IllegalArgumentException("provider=" + provider);
928 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700929
930 boolean result = LocationProvider.propertiesMeetCriteria(
931 p.getName(), p.getProperties(), criteria);
932 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
933 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700934 }
935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700937 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400938 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500939 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 boolean isEnabled = p.isEnabled();
941 String name = p.getName();
Victoria Leasee5601ce2012-10-26 14:34:48 -0700942 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, getCurrentUidBaseLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700944 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700945 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700947 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700948 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700950 }
951 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700952 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
953 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 }
955 }
956
Victoria Leaseb711d572012-10-02 13:14:11 -0700957 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 int listeners = 0;
959
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500960 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700961 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962
963 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
966 if (records != null) {
967 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700968 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 UpdateRecord record = records.get(i);
Victoria Leasee5601ce2012-10-26 14:34:48 -0700970 if (isCurrentUserOrSystemLocked(record.mReceiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700971 // Sends a notification message to the receiver
972 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
973 if (deadReceivers == null) {
974 deadReceivers = new ArrayList<Receiver>();
975 }
976 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700978 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 }
981 }
982
983 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700984 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 removeUpdatesLocked(deadReceivers.get(i));
986 }
987 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700988
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 if (enabled) {
990 p.enable();
991 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700992 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 }
994 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 }
998
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700999 private void applyRequirementsLocked(String provider) {
1000 LocationProviderInterface p = mProvidersByName.get(provider);
1001 if (p == null) return;
1002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001004 WorkSource worksource = new WorkSource();
1005 ProviderRequest providerRequest = new ProviderRequest();
1006
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001008 for (UpdateRecord record : records) {
Victoria Leasee5601ce2012-10-26 14:34:48 -07001009 if (isCurrentUserOrSystemLocked(record.mReceiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001010 LocationRequest locationRequest = record.mRequest;
1011 providerRequest.locationRequests.add(locationRequest);
1012 if (locationRequest.getInterval() < providerRequest.interval) {
1013 providerRequest.reportLocation = true;
1014 providerRequest.interval = locationRequest.getInterval();
1015 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001016 }
1017 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001018
1019 if (providerRequest.reportLocation) {
1020 // calculate who to blame for power
1021 // This is somewhat arbitrary. We pick a threshold interval
1022 // that is slightly higher that the minimum interval, and
1023 // spread the blame across all applications with a request
1024 // under that threshold.
1025 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1026 for (UpdateRecord record : records) {
Victoria Leasee5601ce2012-10-26 14:34:48 -07001027 if (isCurrentUserOrSystemLocked(record.mReceiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001028 LocationRequest locationRequest = record.mRequest;
1029 if (locationRequest.getInterval() <= thresholdInterval) {
1030 worksource.add(record.mReceiver.mUid);
1031 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001032 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001033 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 }
1035 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001036
1037 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1038 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 }
1040
1041 private class UpdateRecord {
1042 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001043 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001045 Location mLastFixBroadcast;
1046 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047
1048 /**
1049 * Note: must be constructed with lock held.
1050 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001051 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001053 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055
1056 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1057 if (records == null) {
1058 records = new ArrayList<UpdateRecord>();
1059 mRecordsByProvider.put(provider, records);
1060 }
1061 if (!records.contains(this)) {
1062 records.add(this);
1063 }
1064 }
1065
1066 /**
1067 * Method to be called when a record will no longer be used. Calling this multiple times
1068 * must have the same effect as calling it once.
1069 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001070 void disposeLocked(boolean removeReceiver) {
1071 // remove from mRecordsByProvider
1072 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1073 if (globalRecords != null) {
1074 globalRecords.remove(this);
1075 }
1076
1077 if (!removeReceiver) return; // the caller will handle the rest
1078
1079 // remove from Receiver#mUpdateRecords
1080 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1081 if (receiverRecords != null) {
1082 receiverRecords.remove(this.mProvider);
1083
1084 // and also remove the Receiver if it has no more update records
1085 if (removeReceiver && receiverRecords.size() == 0) {
1086 removeUpdatesLocked(mReceiver);
1087 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
1090
1091 @Override
1092 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001093 StringBuilder s = new StringBuilder();
1094 s.append("UpdateRecord[");
1095 s.append(mProvider);
1096 s.append(' ').append(mReceiver.mPackageName).append('(');
1097 s.append(mReceiver.mUid).append(')');
1098 s.append(' ').append(mRequest);
1099 s.append(']');
1100 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 }
1103
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001104 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001105 IBinder binder = listener.asBinder();
1106 Receiver receiver = mReceivers.get(binder);
1107 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001108 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001109 mReceivers.put(binder, receiver);
1110
1111 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001112 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001113 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001114 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001115 return null;
1116 }
1117 }
1118 return receiver;
1119 }
1120
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001121 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001122 Receiver receiver = mReceivers.get(intent);
1123 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001124 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001125 mReceivers.put(intent, receiver);
1126 }
1127 return receiver;
1128 }
1129
Victoria Lease37425c32012-10-16 16:08:48 -07001130 /**
1131 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1132 * and consistency requirements.
1133 *
1134 * @param request the LocationRequest from which to create a sanitized version
1135 * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
1136 * constraints
1137 * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
1138 * @return a version of request that meets the given resolution and consistency requirements
1139 * @hide
1140 */
1141 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1142 LocationRequest sanitizedRequest = new LocationRequest(request);
1143 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1144 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001145 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001146 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001147 break;
1148 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001149 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001150 break;
1151 }
1152 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001153 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1154 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001155 }
Victoria Lease37425c32012-10-16 16:08:48 -07001156 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1157 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001158 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001159 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001160 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001161 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001162 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001163 }
Victoria Lease37425c32012-10-16 16:08:48 -07001164 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001165 }
1166
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001167 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001168 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001169 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001170 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001171 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001172 String[] packages = mPackageManager.getPackagesForUid(uid);
1173 if (packages == null) {
1174 throw new SecurityException("invalid UID " + uid);
1175 }
1176 for (String pkg : packages) {
1177 if (packageName.equals(pkg)) return;
1178 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001179 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001180 }
1181
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001182 private void checkPendingIntent(PendingIntent intent) {
1183 if (intent == null) {
1184 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001185 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001186 }
1187
1188 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1189 int pid, int uid, String packageName) {
1190 if (intent == null && listener == null) {
1191 throw new IllegalArgumentException("need eiter listener or intent");
1192 } else if (intent != null && listener != null) {
1193 throw new IllegalArgumentException("cannot register both listener and intent");
1194 } else if (intent != null) {
1195 checkPendingIntent(intent);
1196 return getReceiver(intent, pid, uid, packageName);
1197 } else {
1198 return getReceiver(listener, pid, uid, packageName);
1199 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001200 }
1201
Nick Pellye0fd6932012-07-11 10:26:13 -07001202 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001203 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1204 PendingIntent intent, String packageName) {
1205 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1206 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001207 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1208 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1209 request.getProvider());
1210 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001212 final int pid = Binder.getCallingPid();
1213 final int uid = Binder.getCallingUid();
1214 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001216 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 long identity = Binder.clearCallingIdentity();
1218 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001219 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001220 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 } finally {
1223 Binder.restoreCallingIdentity(identity);
1224 }
1225 }
1226
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001227 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1228 int pid, int uid, String packageName) {
1229 // Figure out the provider. Either its explicitly request (legacy use cases), or
1230 // use the fused provider
1231 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1232 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001233 if (name == null) {
1234 throw new IllegalArgumentException("provider name must not be null");
1235 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236 LocationProviderInterface provider = mProvidersByName.get(name);
1237 if (provider == null) {
1238 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1239 }
1240
1241 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1242 name + " " + request + " from " + packageName + "(" + uid + ")");
1243
1244 UpdateRecord record = new UpdateRecord(name, request, receiver);
1245 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1246 if (oldRecord != null) {
1247 oldRecord.disposeLocked(false);
1248 }
1249
Victoria Leasee5601ce2012-10-26 14:34:48 -07001250 boolean isProviderEnabled = isAllowedBySettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001251 if (isProviderEnabled) {
1252 applyRequirementsLocked(name);
1253 } else {
1254 // Notify the listener that updates are currently disabled
1255 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 }
1257 }
1258
Nick Pellye0fd6932012-07-11 10:26:13 -07001259 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001260 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1261 String packageName) {
1262 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001263
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001264 final int pid = Binder.getCallingPid();
1265 final int uid = Binder.getCallingUid();
1266 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1267
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001268 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001269 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001271 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001272 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001274 } finally {
1275 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 }
1277 }
1278
1279 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001280 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1281
1282 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1283 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1284 synchronized (receiver) {
1285 if (receiver.mPendingBroadcasts > 0) {
1286 decrementPendingBroadcasts();
1287 receiver.mPendingBroadcasts = 0;
1288 }
1289 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 }
1291
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001292 // Record which providers were associated with this listener
1293 HashSet<String> providers = new HashSet<String>();
1294 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1295 if (oldRecords != null) {
1296 // Call dispose() on the obsolete update records.
1297 for (UpdateRecord record : oldRecords.values()) {
1298 record.disposeLocked(false);
1299 }
1300 // Accumulate providers
1301 providers.addAll(oldRecords.keySet());
1302 }
1303
1304 // update provider
Victoria Leasee5601ce2012-10-26 14:34:48 -07001305 int currentUidBase = getCurrentUidBaseLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001306 for (String provider : providers) {
1307 // If provider is already disabled, don't need to do anything
Victoria Leasee5601ce2012-10-26 14:34:48 -07001308 if (!isAllowedBySettingsLocked(provider, currentUidBase)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001309 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 }
1311
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001312 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 }
1314 }
1315
Nick Pellye0fd6932012-07-11 10:26:13 -07001316 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001317 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001318 if (D) Log.d(TAG, "getLastLocation: " + request);
1319 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001320 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001321 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001322 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1323 request.getProvider());
1324 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001325
Victoria Leasee5601ce2012-10-26 14:34:48 -07001326 final int callingUid = Binder.getCallingUid();
1327 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001328 try {
1329 if (mBlacklist.isBlacklisted(packageName)) {
1330 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1331 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001332 return null;
1333 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001334
1335 synchronized (mLock) {
1336 // Figure out the provider. Either its explicitly request (deprecated API's),
1337 // or use the fused provider
1338 String name = request.getProvider();
1339 if (name == null) name = LocationManager.FUSED_PROVIDER;
1340 LocationProviderInterface provider = mProvidersByName.get(name);
1341 if (provider == null) return null;
1342
Victoria Leasee5601ce2012-10-26 14:34:48 -07001343 if (!isAllowedBySettingsLocked(name, callingUid)) {
1344 return null;
1345 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001346
1347 Location location = mLastLocation.get(name);
1348 if (location == null) {
1349 return null;
1350 }
Victoria Lease37425c32012-10-16 16:08:48 -07001351 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001352 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1353 if (noGPSLocation != null) {
1354 return mLocationFudger.getOrCreate(noGPSLocation);
1355 }
Victoria Lease37425c32012-10-16 16:08:48 -07001356 } else {
1357 return location;
Victoria Lease09016ab2012-09-16 12:33:15 -07001358 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001359 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001360 return null;
1361 } finally {
1362 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001363 }
1364 }
1365
1366 @Override
1367 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1368 String packageName) {
1369 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001370 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1371 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001372 checkPendingIntent(intent);
1373 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001374 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1375 request.getProvider());
1376 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001377
Victoria Lease37425c32012-10-16 16:08:48 -07001378 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001379
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001380 // geo-fence manager uses the public location API, need to clear identity
1381 int uid = Binder.getCallingUid();
1382 long identity = Binder.clearCallingIdentity();
1383 try {
Victoria Lease37425c32012-10-16 16:08:48 -07001384 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001385 } finally {
1386 Binder.restoreCallingIdentity(identity);
1387 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001388 }
1389
1390 @Override
1391 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001392 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001393 checkPendingIntent(intent);
1394 checkPackageName(packageName);
1395
1396 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1397
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001398 // geo-fence manager uses the public location API, need to clear identity
1399 long identity = Binder.clearCallingIdentity();
1400 try {
1401 mGeofenceManager.removeFence(geofence, intent);
1402 } finally {
1403 Binder.restoreCallingIdentity(identity);
1404 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001405 }
1406
1407
1408 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001410 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 return false;
1412 }
Victoria Lease37425c32012-10-16 16:08:48 -07001413 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1414 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415
1416 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001417 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001419 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 return false;
1421 }
1422 return true;
1423 }
1424
Nick Pellye0fd6932012-07-11 10:26:13 -07001425 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001427 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001428 try {
1429 mGpsStatusProvider.removeGpsStatusListener(listener);
1430 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001431 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 }
1434 }
1435
Nick Pellye0fd6932012-07-11 10:26:13 -07001436 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001438 if (provider == null) {
1439 // throw NullPointerException to remain compatible with previous implementation
1440 throw new NullPointerException();
1441 }
Victoria Lease37425c32012-10-16 16:08:48 -07001442 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1443 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001446 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447 != PackageManager.PERMISSION_GRANTED)) {
1448 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1449 }
1450
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001451 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001452 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001453 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001454
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001455 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 }
1457 }
1458
Nick Pellye0fd6932012-07-11 10:26:13 -07001459 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001460 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001461 if (Binder.getCallingUid() != Process.myUid()) {
1462 throw new SecurityException(
1463 "calling sendNiResponse from outside of the system is not allowed");
1464 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001465 try {
1466 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001467 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001468 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001469 return false;
1470 }
1471 }
1472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001473 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001474 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001475 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001476 * accessed by the caller
1477 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001478 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001479 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001480 if (mProvidersByName.get(provider) == null) {
1481 return null;
1482 }
1483
Victoria Lease37425c32012-10-16 16:08:48 -07001484 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1485 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001487 LocationProviderInterface p;
1488 synchronized (mLock) {
1489 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 }
1491
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001492 if (p == null) return null;
1493 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 }
1495
Nick Pellye0fd6932012-07-11 10:26:13 -07001496 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001498 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1499 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001500 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1501
Victoria Leasee5601ce2012-10-26 14:34:48 -07001502 final int callingUid = Binder.getCallingUid();
1503 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001504 try {
1505 synchronized (mLock) {
1506 LocationProviderInterface p = mProvidersByName.get(provider);
1507 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001508
Victoria Leasee5601ce2012-10-26 14:34:48 -07001509 return isAllowedBySettingsLocked(provider, callingUid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001510 }
1511 } finally {
1512 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001513 }
1514 }
1515
1516 private void checkCallerIsProvider() {
1517 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1518 == PackageManager.PERMISSION_GRANTED) {
1519 return;
1520 }
1521
1522 // Previously we only used the INSTALL_LOCATION_PROVIDER
1523 // check. But that is system or signature
1524 // protection level which is not flexible enough for
1525 // providers installed oustide the system image. So
1526 // also allow providers with a UID matching the
1527 // currently bound package name
1528
1529 int uid = Binder.getCallingUid();
1530
1531 if (mGeocodeProvider != null) {
1532 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1533 }
1534 for (LocationProviderProxy proxy : mProxyProviders) {
1535 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1536 }
1537 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1538 "or UID of a currently bound location provider");
1539 }
1540
1541 private boolean doesPackageHaveUid(int uid, String packageName) {
1542 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 return false;
1544 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001545 try {
1546 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1547 if (appInfo.uid != uid) {
1548 return false;
1549 }
1550 } catch (NameNotFoundException e) {
1551 return false;
1552 }
1553 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 }
1555
Nick Pellye0fd6932012-07-11 10:26:13 -07001556 @Override
Mike Lockwooda4903f252010-02-17 06:42:23 -05001557 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001558 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001559
Nick Pelly2eeeec22012-07-18 13:13:37 -07001560 if (!location.isComplete()) {
1561 Log.w(TAG, "Dropping incomplete location: " + location);
1562 return;
1563 }
1564
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001565 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1566 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f252010-02-17 06:42:23 -05001567 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001568 mLocationHandler.sendMessageAtFrontOfQueue(m);
1569 }
1570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571
1572 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1573 // Always broadcast the first update
1574 if (lastLoc == null) {
1575 return true;
1576 }
1577
Nick Pellyf1be6862012-05-15 10:53:42 -07001578 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001579 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001580 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001581 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 return false;
1583 }
1584
1585 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001586 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 if (minDistance > 0.0) {
1588 if (loc.distanceTo(lastLoc) <= minDistance) {
1589 return false;
1590 }
1591 }
1592
1593 return true;
1594 }
1595
Mike Lockwooda4903f252010-02-17 06:42:23 -05001596 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001597 if (D) Log.d(TAG, "incoming location: " + location);
1598
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001599 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f252010-02-17 06:42:23 -05001600 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601
Laurent Tu60ec50a2012-10-04 17:00:10 -07001602 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001603 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001604 if (p == null) return;
1605
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001606 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001607 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1608 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001609 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001610 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001611 lastLocation = new Location(provider);
1612 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001613 } else {
1614 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1615 if (noGPSLocation == null && lastNoGPSLocation != null) {
1616 // New location has no no-GPS location: adopt last no-GPS location. This is set
1617 // directly into location because we do not want to notify COARSE clients.
1618 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1619 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001620 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001621 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622
Laurent Tu60ec50a2012-10-04 17:00:10 -07001623 // Skip if there are no UpdateRecords for this provider.
1624 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1625 if (records == null || records.size() == 0) return;
1626
Victoria Lease09016ab2012-09-16 12:33:15 -07001627 // Fetch coarse location
1628 Location coarseLocation = null;
1629 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1630 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1631 }
1632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 // Fetch latest status update time
1634 long newStatusUpdateTime = p.getStatusUpdateTime();
1635
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001636 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001637 Bundle extras = new Bundle();
1638 int status = p.getStatus(extras);
1639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001641 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001644 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001646 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001647
Victoria Leasee5601ce2012-10-26 14:34:48 -07001648 final int receiverUid = receiver.mUid;
1649 if (!isCurrentUserOrSystemLocked(receiverUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001650 if (D) {
Victoria Leasee5601ce2012-10-26 14:34:48 -07001651 Log.d(TAG, "skipping loc update for background uid " + receiverUid +
Victoria Leaseb711d572012-10-02 13:14:11 -07001652 " (current user: " + mCurrentUserId + ", app: " +
1653 receiver.mPackageName + ")");
1654 }
1655 continue;
1656 }
1657
Nick Pelly4035f5a2012-08-17 14:43:49 -07001658 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1659 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1660 receiver.mPackageName);
1661 continue;
1662 }
1663
Victoria Lease09016ab2012-09-16 12:33:15 -07001664 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001665 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1666 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001667 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001668 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001669 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001670 if (notifyLocation != null) {
1671 Location lastLoc = r.mLastFixBroadcast;
1672 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1673 if (lastLoc == null) {
1674 lastLoc = new Location(notifyLocation);
1675 r.mLastFixBroadcast = lastLoc;
1676 } else {
1677 lastLoc.set(notifyLocation);
1678 }
1679 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1680 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1681 receiverDead = true;
1682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 }
1684 }
1685
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001686 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001688 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001690 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001692 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001693 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001694 }
1695 }
1696
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001697 // track expired records
1698 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1699 if (deadUpdateRecords == null) {
1700 deadUpdateRecords = new ArrayList<UpdateRecord>();
1701 }
1702 deadUpdateRecords.add(r);
1703 }
1704 // track dead receivers
1705 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001706 if (deadReceivers == null) {
1707 deadReceivers = new ArrayList<Receiver>();
1708 }
1709 if (!deadReceivers.contains(receiver)) {
1710 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 }
1712 }
1713 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001714
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001715 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001717 for (Receiver receiver : deadReceivers) {
1718 removeUpdatesLocked(receiver);
1719 }
1720 }
1721 if (deadUpdateRecords != null) {
1722 for (UpdateRecord r : deadUpdateRecords) {
1723 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 }
1725 }
1726 }
1727
1728 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 @Override
1730 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001731 switch (msg.what) {
1732 case MSG_LOCATION_CHANGED:
1733 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1734 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 }
1736 }
1737 }
1738
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001739 private void handleLocationChanged(Location location, boolean passive) {
1740 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001741
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001742 if (!passive) {
1743 // notify passive provider of the new location
1744 mPassiveProvider.updateLocation(location);
1745 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001747 synchronized (mLock) {
Victoria Leasee5601ce2012-10-26 14:34:48 -07001748 if (isAllowedBySettingsLocked(provider, getCurrentUidBaseLocked())) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001749 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001752 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753
Mike Lockwoode97ae402010-09-29 15:23:46 -04001754 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1755 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001756 public void onPackageDisappeared(String packageName, int reason) {
1757 // remove all receivers associated with this package name
1758 synchronized (mLock) {
1759 ArrayList<Receiver> deadReceivers = null;
1760
1761 for (Receiver receiver : mReceivers.values()) {
1762 if (receiver.mPackageName.equals(packageName)) {
1763 if (deadReceivers == null) {
1764 deadReceivers = new ArrayList<Receiver>();
1765 }
1766 deadReceivers.add(receiver);
1767 }
1768 }
1769
1770 // perform removal outside of mReceivers loop
1771 if (deadReceivers != null) {
1772 for (Receiver receiver : deadReceivers) {
1773 removeUpdatesLocked(receiver);
1774 }
1775 }
1776 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001777 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001778 };
1779
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 // Wake locks
1781
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001782 private void incrementPendingBroadcasts() {
1783 synchronized (mWakeLock) {
1784 if (mPendingBroadcasts++ == 0) {
1785 try {
1786 mWakeLock.acquire();
1787 log("Acquired wakelock");
1788 } catch (Exception e) {
1789 // This is to catch a runtime exception thrown when we try to release an
1790 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001791 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001792 }
1793 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001794 }
1795 }
1796
1797 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001798 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001799 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001800 try {
1801 // Release wake lock
1802 if (mWakeLock.isHeld()) {
1803 mWakeLock.release();
1804 log("Released wakelock");
1805 } else {
1806 log("Can't release wakelock again!");
1807 }
1808 } catch (Exception e) {
1809 // This is to catch a runtime exception thrown when we try to release an
1810 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001811 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001812 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001813 }
1814 }
1815 }
1816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001817 // Geocoder
1818
Nick Pellye0fd6932012-07-11 10:26:13 -07001819 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001820 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001821 return mGeocodeProvider != null;
1822 }
1823
Nick Pellye0fd6932012-07-11 10:26:13 -07001824 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001826 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001827 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001828 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1829 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001831 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 }
1833
Mike Lockwooda55c3212009-04-15 11:10:11 -04001834
Nick Pellye0fd6932012-07-11 10:26:13 -07001835 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001837 double lowerLeftLatitude, double lowerLeftLongitude,
1838 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001839 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001840
1841 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001842 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1843 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1844 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001846 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001847 }
1848
1849 // Mock Providers
1850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 private void checkMockPermissionsSafe() {
1852 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1853 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1854 if (!allowMocks) {
1855 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1856 }
1857
1858 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1859 PackageManager.PERMISSION_GRANTED) {
1860 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001861 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 }
1863
Nick Pellye0fd6932012-07-11 10:26:13 -07001864 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001865 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 checkMockPermissionsSafe();
1867
Mike Lockwooda4903f252010-02-17 06:42:23 -05001868 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1869 throw new IllegalArgumentException("Cannot mock the passive location provider");
1870 }
1871
Mike Lockwood86328a92009-10-23 08:38:25 -04001872 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001873 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001874 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001875 // remove the real provider if we are replacing GPS or network provider
1876 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001877 || LocationManager.NETWORK_PROVIDER.equals(name)
1878 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001879 LocationProviderInterface p = mProvidersByName.get(name);
1880 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001881 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001882 }
1883 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001884 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1886 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001887 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001888 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001889 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 updateProvidersLocked();
1891 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001892 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001893 }
1894
Nick Pellye0fd6932012-07-11 10:26:13 -07001895 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 public void removeTestProvider(String provider) {
1897 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001898 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001899 MockProvider mockProvider = mMockProviders.get(provider);
1900 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001901 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1902 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001903 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001904 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001905 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001906
1907 // reinstate real provider if available
1908 LocationProviderInterface realProvider = mRealProviders.get(provider);
1909 if (realProvider != null) {
1910 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001911 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001912 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001914 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 }
1916 }
1917
Nick Pellye0fd6932012-07-11 10:26:13 -07001918 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001919 public void setTestProviderLocation(String provider, Location loc) {
1920 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001921 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001922 MockProvider mockProvider = mMockProviders.get(provider);
1923 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1925 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001926 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1927 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001928 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001929 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001930 }
1931 }
1932
Nick Pellye0fd6932012-07-11 10:26:13 -07001933 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001934 public void clearTestProviderLocation(String provider) {
1935 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001936 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001937 MockProvider mockProvider = mMockProviders.get(provider);
1938 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001939 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1940 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001941 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 }
1943 }
1944
Nick Pellye0fd6932012-07-11 10:26:13 -07001945 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001946 public void setTestProviderEnabled(String provider, boolean enabled) {
1947 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001948 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001949 MockProvider mockProvider = mMockProviders.get(provider);
1950 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001951 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1952 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001953 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001955 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 mEnabledProviders.add(provider);
1957 mDisabledProviders.remove(provider);
1958 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001959 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 mEnabledProviders.remove(provider);
1961 mDisabledProviders.add(provider);
1962 }
1963 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001964 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 }
1966 }
1967
Nick Pellye0fd6932012-07-11 10:26:13 -07001968 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 public void clearTestProviderEnabled(String provider) {
1970 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001971 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001972 MockProvider mockProvider = mMockProviders.get(provider);
1973 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1975 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001976 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977 mEnabledProviders.remove(provider);
1978 mDisabledProviders.remove(provider);
1979 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001980 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 }
1982 }
1983
Nick Pellye0fd6932012-07-11 10:26:13 -07001984 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1986 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001987 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001988 MockProvider mockProvider = mMockProviders.get(provider);
1989 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1991 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001992 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 }
1994 }
1995
Nick Pellye0fd6932012-07-11 10:26:13 -07001996 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 public void clearTestProviderStatus(String provider) {
1998 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001999 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002000 MockProvider mockProvider = mMockProviders.get(provider);
2001 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2003 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002004 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 }
2006 }
2007
2008 private void log(String log) {
2009 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002010 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002011 }
2012 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002013
2014 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2016 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2017 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002018 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 + Binder.getCallingPid()
2020 + ", uid=" + Binder.getCallingUid());
2021 return;
2022 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002023
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002024 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002026 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002027 for (Receiver receiver : mReceivers.values()) {
2028 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002031 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2032 pw.println(" " + entry.getKey() + ":");
2033 for (UpdateRecord record : entry.getValue()) {
2034 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002035 }
2036 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002038 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2039 String provider = entry.getKey();
2040 Location location = entry.getValue();
2041 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002042 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002043
Nick Pellye0fd6932012-07-11 10:26:13 -07002044 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002046 if (mEnabledProviders.size() > 0) {
2047 pw.println(" Enabled Providers:");
2048 for (String i : mEnabledProviders) {
2049 pw.println(" " + i);
2050 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 }
2053 if (mDisabledProviders.size() > 0) {
2054 pw.println(" Disabled Providers:");
2055 for (String i : mDisabledProviders) {
2056 pw.println(" " + i);
2057 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002059 pw.append(" ");
2060 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 if (mMockProviders.size() > 0) {
2062 pw.println(" Mock Providers:");
2063 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002064 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002065 }
2066 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002067
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002068 pw.append(" fudger: ");
2069 mLocationFudger.dump(fd, pw, args);
2070
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002071 if (args.length > 0 && "short".equals(args[0])) {
2072 return;
2073 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002074 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002075 pw.print(provider.getName() + " Internal State");
2076 if (provider instanceof LocationProviderProxy) {
2077 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2078 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002079 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002080 pw.println(":");
2081 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002082 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 }
2084 }
2085}