blob: 9416b521a54210ecfc5cf2edf00cb0d6126243ec [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(
Laurent Tu75defb62012-11-01 16:21:52 -0700227 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700228 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 Lease269518e2012-10-29 08:25:39 -0700408 p.switchUser(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700409 }
Victoria Lease38389b62012-09-30 11:44:22 -0700410 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700411 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700412 }
413 }
414
415 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
417 * location updates.
418 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700419 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700420 final int mUid; // uid of receiver
421 final int mPid; // pid of receiver
422 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700423 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 final ILocationListener mListener;
426 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700428
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400429 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700430
Mike Lockwood48f17512009-04-23 09:12:08 -0700431 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700433 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
434 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700437 if (listener != null) {
438 mKey = listener.asBinder();
439 } else {
440 mKey = intent;
441 }
Victoria Lease37425c32012-10-16 16:08:48 -0700442 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700443 mUid = uid;
444 mPid = pid;
445 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 }
447
448 @Override
449 public boolean equals(Object otherObj) {
450 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700451 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 }
453 return false;
454 }
455
456 @Override
457 public int hashCode() {
458 return mKey.hashCode();
459 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 @Override
462 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700463 StringBuilder s = new StringBuilder();
464 s.append("Reciever[");
465 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700467 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700469 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700471 for (String p : mUpdateRecords.keySet()) {
472 s.append(" ").append(mUpdateRecords.get(p).toString());
473 }
474 s.append("]");
475 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 }
477
478 public boolean isListener() {
479 return mListener != null;
480 }
481
482 public boolean isPendingIntent() {
483 return mPendingIntent != null;
484 }
485
486 public ILocationListener getListener() {
487 if (mListener != null) {
488 return mListener;
489 }
490 throw new IllegalStateException("Request for non-existent listener");
491 }
492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
494 if (mListener != null) {
495 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700496 synchronized (this) {
497 // synchronize to ensure incrementPendingBroadcastsLocked()
498 // is called before decrementPendingBroadcasts()
499 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700500 // call this after broadcasting so we do not increment
501 // if we throw an exeption.
502 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 } catch (RemoteException e) {
505 return false;
506 }
507 } else {
508 Intent statusChanged = new Intent();
509 statusChanged.putExtras(extras);
510 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
511 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700512 synchronized (this) {
513 // synchronize to ensure incrementPendingBroadcastsLocked()
514 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700515 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700516 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700517 // call this after broadcasting so we do not increment
518 // if we throw an exeption.
519 incrementPendingBroadcastsLocked();
520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 } catch (PendingIntent.CanceledException e) {
522 return false;
523 }
524 }
525 return true;
526 }
527
528 public boolean callLocationChangedLocked(Location location) {
529 if (mListener != null) {
530 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700531 synchronized (this) {
532 // synchronize to ensure incrementPendingBroadcastsLocked()
533 // is called before decrementPendingBroadcasts()
534 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700535 // call this after broadcasting so we do not increment
536 // if we throw an exeption.
537 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 } catch (RemoteException e) {
540 return false;
541 }
542 } else {
543 Intent locationChanged = new Intent();
544 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
545 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700546 synchronized (this) {
547 // synchronize to ensure incrementPendingBroadcastsLocked()
548 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700549 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700550 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700551 // call this after broadcasting so we do not increment
552 // if we throw an exeption.
553 incrementPendingBroadcastsLocked();
554 }
555 } catch (PendingIntent.CanceledException e) {
556 return false;
557 }
558 }
559 return true;
560 }
561
562 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
563 if (mListener != null) {
564 try {
565 synchronized (this) {
566 // synchronize to ensure incrementPendingBroadcastsLocked()
567 // is called before decrementPendingBroadcasts()
568 if (enabled) {
569 mListener.onProviderEnabled(provider);
570 } else {
571 mListener.onProviderDisabled(provider);
572 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700573 // call this after broadcasting so we do not increment
574 // if we throw an exeption.
575 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700576 }
577 } catch (RemoteException e) {
578 return false;
579 }
580 } else {
581 Intent providerIntent = new Intent();
582 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
583 try {
584 synchronized (this) {
585 // synchronize to ensure incrementPendingBroadcastsLocked()
586 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700587 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700588 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700589 // call this after broadcasting so we do not increment
590 // if we throw an exeption.
591 incrementPendingBroadcastsLocked();
592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 } catch (PendingIntent.CanceledException e) {
594 return false;
595 }
596 }
597 return true;
598 }
599
Nick Pellyf1be6862012-05-15 10:53:42 -0700600 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700602 if (D) Log.d(TAG, "Location listener died");
603
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400604 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 removeUpdatesLocked(this);
606 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700607 synchronized (this) {
608 if (mPendingBroadcasts > 0) {
609 LocationManagerService.this.decrementPendingBroadcasts();
610 mPendingBroadcasts = 0;
611 }
612 }
613 }
614
Nick Pellye0fd6932012-07-11 10:26:13 -0700615 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700616 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
617 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400618 synchronized (this) {
619 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700620 }
621 }
622
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400623 // this must be called while synchronized by caller in a synchronized block
624 // containing the sending of the broadcaset
625 private void incrementPendingBroadcastsLocked() {
626 if (mPendingBroadcasts++ == 0) {
627 LocationManagerService.this.incrementPendingBroadcasts();
628 }
629 }
630
631 private void decrementPendingBroadcastsLocked() {
632 if (--mPendingBroadcasts == 0) {
633 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700634 }
635 }
636 }
637
Nick Pellye0fd6932012-07-11 10:26:13 -0700638 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700639 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400640 //Do not use getReceiver here as that will add the ILocationListener to
641 //the receiver list if it is not found. If it is not found then the
642 //LocationListener was removed when it had a pending broadcast and should
643 //not be added back.
644 IBinder binder = listener.asBinder();
645 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700646 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400647 synchronized (receiver) {
648 // so wakelock calls will succeed
649 long identity = Binder.clearCallingIdentity();
650 receiver.decrementPendingBroadcastsLocked();
651 Binder.restoreCallingIdentity(identity);
652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654 }
655
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700656 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400657 mProviders.add(provider);
658 mProvidersByName.put(provider.getName(), provider);
659 }
660
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 private void removeProviderLocked(LocationProviderInterface provider) {
662 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400663 mProviders.remove(provider);
664 mProvidersByName.remove(provider.getName());
665 }
666
Mike Lockwood3d12b512009-04-21 23:25:35 -0700667
Victoria Lease269518e2012-10-29 08:25:39 -0700668 private boolean isAllowedBySettingsLocked(String provider, int userId) {
669 if (userId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700670 return false;
671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 if (mEnabledProviders.contains(provider)) {
673 return true;
674 }
675 if (mDisabledProviders.contains(provider)) {
676 return false;
677 }
678 // Use system settings
679 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680
Victoria Leaseb711d572012-10-02 13:14:11 -0700681 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 }
683
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700684 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700685 * Returns the permission string associated with the specified resolution level.
686 *
687 * @param resolutionLevel the resolution level
688 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700689 */
Victoria Lease37425c32012-10-16 16:08:48 -0700690 private String getResolutionPermission(int resolutionLevel) {
691 switch (resolutionLevel) {
692 case RESOLUTION_LEVEL_FINE:
693 return android.Manifest.permission.ACCESS_FINE_LOCATION;
694 case RESOLUTION_LEVEL_COARSE:
695 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
696 default:
697 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700699 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700700
Victoria Leaseda479c52012-10-15 15:24:16 -0700701 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700702 * Returns the resolution level allowed to the given PID/UID pair.
703 *
704 * @param pid the PID
705 * @param uid the UID
706 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700707 */
Victoria Lease37425c32012-10-16 16:08:48 -0700708 private int getAllowedResolutionLevel(int pid, int uid) {
709 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
710 pid, uid) == PackageManager.PERMISSION_GRANTED) {
711 return RESOLUTION_LEVEL_FINE;
712 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
713 pid, uid) == PackageManager.PERMISSION_GRANTED) {
714 return RESOLUTION_LEVEL_COARSE;
715 } else {
716 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700717 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700718 }
719
720 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700721 * Returns the resolution level allowed to the caller
722 *
723 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700724 */
Victoria Lease37425c32012-10-16 16:08:48 -0700725 private int getCallerAllowedResolutionLevel() {
726 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
727 }
728
729 /**
730 * Throw SecurityException if specified resolution level is insufficient to use geofences.
731 *
732 * @param allowedResolutionLevel resolution level allowed to caller
733 */
734 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
735 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700736 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 }
739
Victoria Lease37425c32012-10-16 16:08:48 -0700740 /**
741 * Return the minimum resolution level required to use the specified location provider.
742 *
743 * @param provider the name of the location provider
744 * @return minimum resolution level required for provider
745 */
746 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700747 if (LocationManager.GPS_PROVIDER.equals(provider) ||
748 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
749 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700750 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700751 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
752 LocationManager.FUSED_PROVIDER.equals(provider)) {
753 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700754 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700755 } else {
756 // mock providers
757 LocationProviderInterface lp = mMockProviders.get(provider);
758 if (lp != null) {
759 ProviderProperties properties = lp.getProperties();
760 if (properties != null) {
761 if (properties.mRequiresSatellite) {
762 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700763 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700764 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
765 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700766 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700767 }
768 }
769 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700770 }
Victoria Lease37425c32012-10-16 16:08:48 -0700771 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700772 }
773
Victoria Lease37425c32012-10-16 16:08:48 -0700774 /**
775 * Throw SecurityException if specified resolution level is insufficient to use the named
776 * location provider.
777 *
778 * @param allowedResolutionLevel resolution level allowed to caller
779 * @param providerName the name of the location provider
780 */
781 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
782 String providerName) {
783 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
784 if (allowedResolutionLevel < requiredResolutionLevel) {
785 switch (requiredResolutionLevel) {
786 case RESOLUTION_LEVEL_FINE:
787 throw new SecurityException("\"" + providerName + "\" location provider " +
788 "requires ACCESS_FINE_LOCATION permission.");
789 case RESOLUTION_LEVEL_COARSE:
790 throw new SecurityException("\"" + providerName + "\" location provider " +
791 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
792 default:
793 throw new SecurityException("Insufficient permission for \"" + providerName +
794 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700795 }
796 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700797 }
798
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700799 /**
800 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700801 * fused, also including ones that are not permitted to
802 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700803 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700804 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700806 ArrayList<String> out;
807 synchronized (mLock) {
808 out = new ArrayList<String>(mProviders.size());
809 for (LocationProviderInterface provider : mProviders) {
810 String name = provider.getName();
811 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700812 continue;
813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 out.add(name);
815 }
816 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700817
818 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 return out;
820 }
821
Mike Lockwood03ca2162010-04-01 08:10:09 -0700822 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700823 * Return all providers by name, that match criteria and are optionally
824 * enabled.
825 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700826 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700827 @Override
828 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700829 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700830 ArrayList<String> out;
Victoria Lease269518e2012-10-29 08:25:39 -0700831 int callingUserId = UserHandle.getCallingUserId();
832 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700833 try {
834 synchronized (mLock) {
835 out = new ArrayList<String>(mProviders.size());
836 for (LocationProviderInterface provider : mProviders) {
837 String name = provider.getName();
838 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700839 continue;
840 }
Victoria Lease37425c32012-10-16 16:08:48 -0700841 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease269518e2012-10-29 08:25:39 -0700842 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700843 continue;
844 }
845 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
846 name, provider.getProperties(), criteria)) {
847 continue;
848 }
849 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700850 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700851 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700852 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700853 } finally {
854 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700855 }
856
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700857 if (D) Log.d(TAG, "getProviders()=" + out);
858 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700859 }
860
861 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700862 * Return the name of the best provider given a Criteria object.
863 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700864 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700865 * has been deprecated as well. So this method now uses
866 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700867 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700868 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700869 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700870 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700871
872 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700873 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700874 result = pickBest(providers);
875 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
876 return result;
877 }
878 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700879 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700880 result = pickBest(providers);
881 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
882 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700883 }
884
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700885 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700886 return null;
887 }
888
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700889 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700890 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700891 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700892 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
893 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700894 } else {
895 return providers.get(0);
896 }
897 }
898
Nick Pellye0fd6932012-07-11 10:26:13 -0700899 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700900 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
901 LocationProviderInterface p = mProvidersByName.get(provider);
902 if (p == null) {
903 throw new IllegalArgumentException("provider=" + provider);
904 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700905
906 boolean result = LocationProvider.propertiesMeetCriteria(
907 p.getName(), p.getProperties(), criteria);
908 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
909 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700910 }
911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700913 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400914 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500915 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 boolean isEnabled = p.isEnabled();
917 String name = p.getName();
Victoria Lease269518e2012-10-29 08:25:39 -0700918 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700920 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700921 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700923 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700924 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700926 }
927 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700928 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
929 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 }
931 }
932
Victoria Leaseb711d572012-10-02 13:14:11 -0700933 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 int listeners = 0;
935
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500936 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700937 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938
939 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
942 if (records != null) {
943 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700944 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -0700946 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700947 // Sends a notification message to the receiver
948 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
949 if (deadReceivers == null) {
950 deadReceivers = new ArrayList<Receiver>();
951 }
952 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700954 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 }
957 }
958
959 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700960 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 removeUpdatesLocked(deadReceivers.get(i));
962 }
963 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 if (enabled) {
966 p.enable();
967 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700968 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 }
970 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 }
974
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700975 private void applyRequirementsLocked(String provider) {
976 LocationProviderInterface p = mProvidersByName.get(provider);
977 if (p == null) return;
978
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700980 WorkSource worksource = new WorkSource();
981 ProviderRequest providerRequest = new ProviderRequest();
982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700984 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -0700985 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700986 LocationRequest locationRequest = record.mRequest;
987 providerRequest.locationRequests.add(locationRequest);
988 if (locationRequest.getInterval() < providerRequest.interval) {
989 providerRequest.reportLocation = true;
990 providerRequest.interval = locationRequest.getInterval();
991 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700992 }
993 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700994
995 if (providerRequest.reportLocation) {
996 // calculate who to blame for power
997 // This is somewhat arbitrary. We pick a threshold interval
998 // that is slightly higher that the minimum interval, and
999 // spread the blame across all applications with a request
1000 // under that threshold.
1001 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1002 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001003 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001004 LocationRequest locationRequest = record.mRequest;
1005 if (locationRequest.getInterval() <= thresholdInterval) {
1006 worksource.add(record.mReceiver.mUid);
1007 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001008 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001009 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
1011 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001012
1013 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1014 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 }
1016
1017 private class UpdateRecord {
1018 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001019 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001021 Location mLastFixBroadcast;
1022 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023
1024 /**
1025 * Note: must be constructed with lock held.
1026 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001027 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001029 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031
1032 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1033 if (records == null) {
1034 records = new ArrayList<UpdateRecord>();
1035 mRecordsByProvider.put(provider, records);
1036 }
1037 if (!records.contains(this)) {
1038 records.add(this);
1039 }
1040 }
1041
1042 /**
1043 * Method to be called when a record will no longer be used. Calling this multiple times
1044 * must have the same effect as calling it once.
1045 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001046 void disposeLocked(boolean removeReceiver) {
1047 // remove from mRecordsByProvider
1048 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1049 if (globalRecords != null) {
1050 globalRecords.remove(this);
1051 }
1052
1053 if (!removeReceiver) return; // the caller will handle the rest
1054
1055 // remove from Receiver#mUpdateRecords
1056 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1057 if (receiverRecords != null) {
1058 receiverRecords.remove(this.mProvider);
1059
1060 // and also remove the Receiver if it has no more update records
1061 if (removeReceiver && receiverRecords.size() == 0) {
1062 removeUpdatesLocked(mReceiver);
1063 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001064 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 }
1066
1067 @Override
1068 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001069 StringBuilder s = new StringBuilder();
1070 s.append("UpdateRecord[");
1071 s.append(mProvider);
1072 s.append(' ').append(mReceiver.mPackageName).append('(');
1073 s.append(mReceiver.mUid).append(')');
1074 s.append(' ').append(mRequest);
1075 s.append(']');
1076 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 }
1079
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001080 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001081 IBinder binder = listener.asBinder();
1082 Receiver receiver = mReceivers.get(binder);
1083 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001084 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001085 mReceivers.put(binder, receiver);
1086
1087 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001088 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001089 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001090 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001091 return null;
1092 }
1093 }
1094 return receiver;
1095 }
1096
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001097 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001098 Receiver receiver = mReceivers.get(intent);
1099 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001100 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001101 mReceivers.put(intent, receiver);
1102 }
1103 return receiver;
1104 }
1105
Victoria Lease37425c32012-10-16 16:08:48 -07001106 /**
1107 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1108 * and consistency requirements.
1109 *
1110 * @param request the LocationRequest from which to create a sanitized version
1111 * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
1112 * constraints
1113 * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
1114 * @return a version of request that meets the given resolution and consistency requirements
1115 * @hide
1116 */
1117 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1118 LocationRequest sanitizedRequest = new LocationRequest(request);
1119 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1120 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001121 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001122 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001123 break;
1124 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001125 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001126 break;
1127 }
1128 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001129 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1130 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001131 }
Victoria Lease37425c32012-10-16 16:08:48 -07001132 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1133 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001134 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001135 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001136 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001137 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001138 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001139 }
Victoria Lease37425c32012-10-16 16:08:48 -07001140 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001141 }
1142
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001143 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001144 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001145 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001146 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001147 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001148 String[] packages = mPackageManager.getPackagesForUid(uid);
1149 if (packages == null) {
1150 throw new SecurityException("invalid UID " + uid);
1151 }
1152 for (String pkg : packages) {
1153 if (packageName.equals(pkg)) return;
1154 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001155 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001156 }
1157
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001158 private void checkPendingIntent(PendingIntent intent) {
1159 if (intent == null) {
1160 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001161 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001162 }
1163
1164 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1165 int pid, int uid, String packageName) {
1166 if (intent == null && listener == null) {
1167 throw new IllegalArgumentException("need eiter listener or intent");
1168 } else if (intent != null && listener != null) {
1169 throw new IllegalArgumentException("cannot register both listener and intent");
1170 } else if (intent != null) {
1171 checkPendingIntent(intent);
1172 return getReceiver(intent, pid, uid, packageName);
1173 } else {
1174 return getReceiver(listener, pid, uid, packageName);
1175 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001176 }
1177
Nick Pellye0fd6932012-07-11 10:26:13 -07001178 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001179 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1180 PendingIntent intent, String packageName) {
1181 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1182 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001183 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1184 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1185 request.getProvider());
1186 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001188 final int pid = Binder.getCallingPid();
1189 final int uid = Binder.getCallingUid();
1190 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001192 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 long identity = Binder.clearCallingIdentity();
1194 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001195 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001196 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 } finally {
1199 Binder.restoreCallingIdentity(identity);
1200 }
1201 }
1202
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001203 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1204 int pid, int uid, String packageName) {
1205 // Figure out the provider. Either its explicitly request (legacy use cases), or
1206 // use the fused provider
1207 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1208 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001209 if (name == null) {
1210 throw new IllegalArgumentException("provider name must not be null");
1211 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001212 LocationProviderInterface provider = mProvidersByName.get(name);
1213 if (provider == null) {
1214 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1215 }
1216
1217 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1218 name + " " + request + " from " + packageName + "(" + uid + ")");
1219
1220 UpdateRecord record = new UpdateRecord(name, request, receiver);
1221 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1222 if (oldRecord != null) {
1223 oldRecord.disposeLocked(false);
1224 }
1225
Victoria Lease269518e2012-10-29 08:25:39 -07001226 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001227 if (isProviderEnabled) {
1228 applyRequirementsLocked(name);
1229 } else {
1230 // Notify the listener that updates are currently disabled
1231 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 }
1233 }
1234
Nick Pellye0fd6932012-07-11 10:26:13 -07001235 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1237 String packageName) {
1238 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001239
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001240 final int pid = Binder.getCallingPid();
1241 final int uid = Binder.getCallingUid();
1242 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1243
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001244 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001245 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001247 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001248 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001250 } finally {
1251 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 }
1253 }
1254
1255 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001256 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1257
1258 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1259 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1260 synchronized (receiver) {
1261 if (receiver.mPendingBroadcasts > 0) {
1262 decrementPendingBroadcasts();
1263 receiver.mPendingBroadcasts = 0;
1264 }
1265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 }
1267
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001268 // Record which providers were associated with this listener
1269 HashSet<String> providers = new HashSet<String>();
1270 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1271 if (oldRecords != null) {
1272 // Call dispose() on the obsolete update records.
1273 for (UpdateRecord record : oldRecords.values()) {
1274 record.disposeLocked(false);
1275 }
1276 // Accumulate providers
1277 providers.addAll(oldRecords.keySet());
1278 }
1279
1280 // update provider
1281 for (String provider : providers) {
1282 // If provider is already disabled, don't need to do anything
Victoria Lease269518e2012-10-29 08:25:39 -07001283 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 }
1286
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001287 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 }
1289 }
1290
Nick Pellye0fd6932012-07-11 10:26:13 -07001291 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001292 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001293 if (D) Log.d(TAG, "getLastLocation: " + request);
1294 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001295 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001296 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001297 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1298 request.getProvider());
1299 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001300
Victoria Lease269518e2012-10-29 08:25:39 -07001301 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001302 try {
1303 if (mBlacklist.isBlacklisted(packageName)) {
1304 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1305 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001306 return null;
1307 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001308
1309 synchronized (mLock) {
1310 // Figure out the provider. Either its explicitly request (deprecated API's),
1311 // or use the fused provider
1312 String name = request.getProvider();
1313 if (name == null) name = LocationManager.FUSED_PROVIDER;
1314 LocationProviderInterface provider = mProvidersByName.get(name);
1315 if (provider == null) return null;
1316
Victoria Lease269518e2012-10-29 08:25:39 -07001317 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001318
1319 Location location = mLastLocation.get(name);
1320 if (location == null) {
1321 return null;
1322 }
Victoria Lease37425c32012-10-16 16:08:48 -07001323 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001324 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1325 if (noGPSLocation != null) {
1326 return mLocationFudger.getOrCreate(noGPSLocation);
1327 }
Victoria Lease37425c32012-10-16 16:08:48 -07001328 } else {
1329 return location;
Victoria Lease09016ab2012-09-16 12:33:15 -07001330 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001331 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001332 return null;
1333 } finally {
1334 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001335 }
1336 }
1337
1338 @Override
1339 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1340 String packageName) {
1341 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001342 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1343 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001344 checkPendingIntent(intent);
1345 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001346 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1347 request.getProvider());
1348 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001349
Victoria Lease37425c32012-10-16 16:08:48 -07001350 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001351
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001352 // geo-fence manager uses the public location API, need to clear identity
1353 int uid = Binder.getCallingUid();
1354 long identity = Binder.clearCallingIdentity();
1355 try {
Victoria Lease37425c32012-10-16 16:08:48 -07001356 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001357 } finally {
1358 Binder.restoreCallingIdentity(identity);
1359 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001360 }
1361
1362 @Override
1363 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001364 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001365 checkPendingIntent(intent);
1366 checkPackageName(packageName);
1367
1368 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1369
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001370 // geo-fence manager uses the public location API, need to clear identity
1371 long identity = Binder.clearCallingIdentity();
1372 try {
1373 mGeofenceManager.removeFence(geofence, intent);
1374 } finally {
1375 Binder.restoreCallingIdentity(identity);
1376 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001377 }
1378
1379
1380 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001382 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 return false;
1384 }
Victoria Lease37425c32012-10-16 16:08:48 -07001385 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1386 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387
1388 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001389 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001391 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 return false;
1393 }
1394 return true;
1395 }
1396
Nick Pellye0fd6932012-07-11 10:26:13 -07001397 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001399 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001400 try {
1401 mGpsStatusProvider.removeGpsStatusListener(listener);
1402 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001403 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001404 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 }
1406 }
1407
Nick Pellye0fd6932012-07-11 10:26:13 -07001408 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001410 if (provider == null) {
1411 // throw NullPointerException to remain compatible with previous implementation
1412 throw new NullPointerException();
1413 }
Victoria Lease37425c32012-10-16 16:08:48 -07001414 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1415 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001418 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 != PackageManager.PERMISSION_GRANTED)) {
1420 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1421 }
1422
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001423 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001424 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001425 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001426
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001427 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 }
1429 }
1430
Nick Pellye0fd6932012-07-11 10:26:13 -07001431 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001432 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001433 if (Binder.getCallingUid() != Process.myUid()) {
1434 throw new SecurityException(
1435 "calling sendNiResponse from outside of the system is not allowed");
1436 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001437 try {
1438 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001439 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001440 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001441 return false;
1442 }
1443 }
1444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001446 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001447 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 * accessed by the caller
1449 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001450 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001451 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001452 if (mProvidersByName.get(provider) == null) {
1453 return null;
1454 }
1455
Victoria Lease37425c32012-10-16 16:08:48 -07001456 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1457 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001459 LocationProviderInterface p;
1460 synchronized (mLock) {
1461 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 }
1463
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001464 if (p == null) return null;
1465 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 }
1467
Nick Pellye0fd6932012-07-11 10:26:13 -07001468 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001470 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1471 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001472 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1473
Victoria Lease269518e2012-10-29 08:25:39 -07001474 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001475 try {
1476 synchronized (mLock) {
1477 LocationProviderInterface p = mProvidersByName.get(provider);
1478 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001479
Victoria Lease269518e2012-10-29 08:25:39 -07001480 return isAllowedBySettingsLocked(provider, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -07001481 }
1482 } finally {
1483 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001484 }
1485 }
1486
1487 private void checkCallerIsProvider() {
1488 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1489 == PackageManager.PERMISSION_GRANTED) {
1490 return;
1491 }
1492
1493 // Previously we only used the INSTALL_LOCATION_PROVIDER
1494 // check. But that is system or signature
1495 // protection level which is not flexible enough for
1496 // providers installed oustide the system image. So
1497 // also allow providers with a UID matching the
1498 // currently bound package name
1499
1500 int uid = Binder.getCallingUid();
1501
1502 if (mGeocodeProvider != null) {
1503 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1504 }
1505 for (LocationProviderProxy proxy : mProxyProviders) {
1506 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1507 }
1508 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1509 "or UID of a currently bound location provider");
1510 }
1511
1512 private boolean doesPackageHaveUid(int uid, String packageName) {
1513 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 return false;
1515 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001516 try {
1517 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1518 if (appInfo.uid != uid) {
1519 return false;
1520 }
1521 } catch (NameNotFoundException e) {
1522 return false;
1523 }
1524 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 }
1526
Nick Pellye0fd6932012-07-11 10:26:13 -07001527 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001528 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001529 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001530
Nick Pelly2eeeec22012-07-18 13:13:37 -07001531 if (!location.isComplete()) {
1532 Log.w(TAG, "Dropping incomplete location: " + location);
1533 return;
1534 }
1535
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001536 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1537 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001538 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001539 mLocationHandler.sendMessageAtFrontOfQueue(m);
1540 }
1541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542
Laurent Tu75defb62012-11-01 16:21:52 -07001543 private static boolean shouldBroadcastSafe(
1544 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 // Always broadcast the first update
1546 if (lastLoc == null) {
1547 return true;
1548 }
1549
Nick Pellyf1be6862012-05-15 10:53:42 -07001550 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001551 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001552 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001553 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 return false;
1555 }
1556
1557 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001558 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 if (minDistance > 0.0) {
1560 if (loc.distanceTo(lastLoc) <= minDistance) {
1561 return false;
1562 }
1563 }
1564
Laurent Tu75defb62012-11-01 16:21:52 -07001565 // Check whether sufficient number of udpates is left
1566 if (record.mRequest.getNumUpdates() <= 0) {
1567 return false;
1568 }
1569
1570 // Check whether the expiry date has passed
1571 if (record.mRequest.getExpireAt() < now) {
1572 return false;
1573 }
1574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 return true;
1576 }
1577
Mike Lockwooda4903f22010-02-17 06:42:23 -05001578 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001579 if (D) Log.d(TAG, "incoming location: " + location);
1580
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001581 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001582 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583
Laurent Tu60ec50a2012-10-04 17:00:10 -07001584 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001585 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001586 if (p == null) return;
1587
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001588 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001589 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1590 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001591 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001592 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001593 lastLocation = new Location(provider);
1594 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001595 } else {
1596 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1597 if (noGPSLocation == null && lastNoGPSLocation != null) {
1598 // New location has no no-GPS location: adopt last no-GPS location. This is set
1599 // directly into location because we do not want to notify COARSE clients.
1600 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1601 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001602 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001603 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604
Laurent Tu60ec50a2012-10-04 17:00:10 -07001605 // Skip if there are no UpdateRecords for this provider.
1606 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1607 if (records == null || records.size() == 0) return;
1608
Victoria Lease09016ab2012-09-16 12:33:15 -07001609 // Fetch coarse location
1610 Location coarseLocation = null;
1611 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1612 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1613 }
1614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 // Fetch latest status update time
1616 long newStatusUpdateTime = p.getStatusUpdateTime();
1617
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001618 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 Bundle extras = new Bundle();
1620 int status = p.getStatus(extras);
1621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001623 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001626 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001628 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001629
Victoria Lease269518e2012-10-29 08:25:39 -07001630 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1631 if (receiverUserId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001632 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001633 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001634 " (current user: " + mCurrentUserId + ", app: " +
1635 receiver.mPackageName + ")");
1636 }
1637 continue;
1638 }
1639
Nick Pelly4035f5a2012-08-17 14:43:49 -07001640 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1641 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1642 receiver.mPackageName);
1643 continue;
1644 }
1645
Victoria Lease09016ab2012-09-16 12:33:15 -07001646 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001647 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1648 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001649 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001650 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001651 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001652 if (notifyLocation != null) {
1653 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001654 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001655 if (lastLoc == null) {
1656 lastLoc = new Location(notifyLocation);
1657 r.mLastFixBroadcast = lastLoc;
1658 } else {
1659 lastLoc.set(notifyLocation);
1660 }
1661 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1662 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1663 receiverDead = true;
1664 }
Laurent Tu75defb62012-11-01 16:21:52 -07001665 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 }
1667 }
1668
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001669 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001671 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001673 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001675 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001676 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001677 }
1678 }
1679
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001680 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001681 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001682 if (deadUpdateRecords == null) {
1683 deadUpdateRecords = new ArrayList<UpdateRecord>();
1684 }
1685 deadUpdateRecords.add(r);
1686 }
1687 // track dead receivers
1688 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001689 if (deadReceivers == null) {
1690 deadReceivers = new ArrayList<Receiver>();
1691 }
1692 if (!deadReceivers.contains(receiver)) {
1693 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 }
1695 }
1696 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001697
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001698 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001700 for (Receiver receiver : deadReceivers) {
1701 removeUpdatesLocked(receiver);
1702 }
1703 }
1704 if (deadUpdateRecords != null) {
1705 for (UpdateRecord r : deadUpdateRecords) {
1706 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 }
1708 }
1709 }
1710
1711 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 @Override
1713 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001714 switch (msg.what) {
1715 case MSG_LOCATION_CHANGED:
1716 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1717 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 }
1719 }
1720 }
1721
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001722 private void handleLocationChanged(Location location, boolean passive) {
1723 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001724
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001725 if (!passive) {
1726 // notify passive provider of the new location
1727 mPassiveProvider.updateLocation(location);
1728 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001730 synchronized (mLock) {
Victoria Lease269518e2012-10-29 08:25:39 -07001731 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001732 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736
Mike Lockwoode97ae402010-09-29 15:23:46 -04001737 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1738 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001739 public void onPackageDisappeared(String packageName, int reason) {
1740 // remove all receivers associated with this package name
1741 synchronized (mLock) {
1742 ArrayList<Receiver> deadReceivers = null;
1743
1744 for (Receiver receiver : mReceivers.values()) {
1745 if (receiver.mPackageName.equals(packageName)) {
1746 if (deadReceivers == null) {
1747 deadReceivers = new ArrayList<Receiver>();
1748 }
1749 deadReceivers.add(receiver);
1750 }
1751 }
1752
1753 // perform removal outside of mReceivers loop
1754 if (deadReceivers != null) {
1755 for (Receiver receiver : deadReceivers) {
1756 removeUpdatesLocked(receiver);
1757 }
1758 }
1759 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001760 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001761 };
1762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 // Wake locks
1764
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001765 private void incrementPendingBroadcasts() {
1766 synchronized (mWakeLock) {
1767 if (mPendingBroadcasts++ == 0) {
1768 try {
1769 mWakeLock.acquire();
1770 log("Acquired wakelock");
1771 } catch (Exception e) {
1772 // This is to catch a runtime exception thrown when we try to release an
1773 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001774 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001775 }
1776 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001777 }
1778 }
1779
1780 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001781 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001782 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001783 try {
1784 // Release wake lock
1785 if (mWakeLock.isHeld()) {
1786 mWakeLock.release();
1787 log("Released wakelock");
1788 } else {
1789 log("Can't release wakelock again!");
1790 }
1791 } catch (Exception e) {
1792 // This is to catch a runtime exception thrown when we try to release an
1793 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001794 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001795 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001796 }
1797 }
1798 }
1799
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800 // Geocoder
1801
Nick Pellye0fd6932012-07-11 10:26:13 -07001802 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001803 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001804 return mGeocodeProvider != null;
1805 }
1806
Nick Pellye0fd6932012-07-11 10:26:13 -07001807 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001809 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001810 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001811 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1812 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001814 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 }
1816
Mike Lockwooda55c3212009-04-15 11:10:11 -04001817
Nick Pellye0fd6932012-07-11 10:26:13 -07001818 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001820 double lowerLeftLatitude, double lowerLeftLongitude,
1821 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001822 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001823
1824 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001825 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1826 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1827 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001828 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001829 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 }
1831
1832 // Mock Providers
1833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 private void checkMockPermissionsSafe() {
1835 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1836 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1837 if (!allowMocks) {
1838 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1839 }
1840
1841 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1842 PackageManager.PERMISSION_GRANTED) {
1843 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001844 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 }
1846
Nick Pellye0fd6932012-07-11 10:26:13 -07001847 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001848 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 checkMockPermissionsSafe();
1850
Mike Lockwooda4903f22010-02-17 06:42:23 -05001851 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1852 throw new IllegalArgumentException("Cannot mock the passive location provider");
1853 }
1854
Mike Lockwood86328a92009-10-23 08:38:25 -04001855 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001856 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001857 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001858 // remove the real provider if we are replacing GPS or network provider
1859 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001860 || LocationManager.NETWORK_PROVIDER.equals(name)
1861 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001862 LocationProviderInterface p = mProvidersByName.get(name);
1863 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001864 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001865 }
1866 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001867 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001868 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1869 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001870 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001871 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001872 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873 updateProvidersLocked();
1874 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001875 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 }
1877
Nick Pellye0fd6932012-07-11 10:26:13 -07001878 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 public void removeTestProvider(String provider) {
1880 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001881 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001882 MockProvider mockProvider = mMockProviders.get(provider);
1883 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1885 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001886 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001887 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001888 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001889
1890 // reinstate real provider if available
1891 LocationProviderInterface realProvider = mRealProviders.get(provider);
1892 if (realProvider != null) {
1893 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001894 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001895 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001897 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 }
1899 }
1900
Nick Pellye0fd6932012-07-11 10:26:13 -07001901 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 public void setTestProviderLocation(String provider, Location loc) {
1903 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001904 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001905 MockProvider mockProvider = mMockProviders.get(provider);
1906 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001907 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1908 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001909 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1910 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001911 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001912 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 }
1914 }
1915
Nick Pellye0fd6932012-07-11 10:26:13 -07001916 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 public void clearTestProviderLocation(String provider) {
1918 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001919 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001920 MockProvider mockProvider = mMockProviders.get(provider);
1921 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1923 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001924 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925 }
1926 }
1927
Nick Pellye0fd6932012-07-11 10:26:13 -07001928 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 public void setTestProviderEnabled(String provider, boolean enabled) {
1930 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001931 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001932 MockProvider mockProvider = mMockProviders.get(provider);
1933 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001934 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1935 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001936 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001938 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001939 mEnabledProviders.add(provider);
1940 mDisabledProviders.remove(provider);
1941 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001942 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 mEnabledProviders.remove(provider);
1944 mDisabledProviders.add(provider);
1945 }
1946 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001947 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001948 }
1949 }
1950
Nick Pellye0fd6932012-07-11 10:26:13 -07001951 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 public void clearTestProviderEnabled(String provider) {
1953 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001954 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001955 MockProvider mockProvider = mMockProviders.get(provider);
1956 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1958 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001959 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 mEnabledProviders.remove(provider);
1961 mDisabledProviders.remove(provider);
1962 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001963 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001964 }
1965 }
1966
Nick Pellye0fd6932012-07-11 10:26:13 -07001967 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1969 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001970 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001971 MockProvider mockProvider = mMockProviders.get(provider);
1972 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1974 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001975 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 }
1977 }
1978
Nick Pellye0fd6932012-07-11 10:26:13 -07001979 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 public void clearTestProviderStatus(String provider) {
1981 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001982 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001983 MockProvider mockProvider = mMockProviders.get(provider);
1984 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1986 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001987 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 }
1989 }
1990
1991 private void log(String log) {
1992 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001993 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 }
1995 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001996
1997 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1999 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2000 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002001 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 + Binder.getCallingPid()
2003 + ", uid=" + Binder.getCallingUid());
2004 return;
2005 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002006
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002007 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002010 for (Receiver receiver : mReceivers.values()) {
2011 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002014 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2015 pw.println(" " + entry.getKey() + ":");
2016 for (UpdateRecord record : entry.getValue()) {
2017 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 }
2019 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002021 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2022 String provider = entry.getKey();
2023 Location location = entry.getValue();
2024 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002026
Nick Pellye0fd6932012-07-11 10:26:13 -07002027 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 if (mEnabledProviders.size() > 0) {
2030 pw.println(" Enabled Providers:");
2031 for (String i : mEnabledProviders) {
2032 pw.println(" " + i);
2033 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002035 }
2036 if (mDisabledProviders.size() > 0) {
2037 pw.println(" Disabled Providers:");
2038 for (String i : mDisabledProviders) {
2039 pw.println(" " + i);
2040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002041 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002042 pw.append(" ");
2043 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 if (mMockProviders.size() > 0) {
2045 pw.println(" Mock Providers:");
2046 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002047 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 }
2049 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002050
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002051 pw.append(" fudger: ");
2052 mLocationFudger.dump(fd, pw, args);
2053
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002054 if (args.length > 0 && "short".equals(args[0])) {
2055 return;
2056 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002057 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002058 pw.print(provider.getName() + " Internal State");
2059 if (provider instanceof LocationProviderProxy) {
2060 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2061 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002062 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002063 pw.println(":");
2064 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002065 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 }
2067 }
2068}