blob: baacac69550b4da3d3b270be3c2fc938293df9da [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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 private static final String ACCESS_FINE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070097 android.Manifest.permission.ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 private static final String ACCESS_COARSE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070099 android.Manifest.permission.ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700101 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700103 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400104 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700105 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
106
107 private static final String NETWORK_LOCATION_SERVICE_ACTION =
108 "com.android.location.service.v2.NetworkLocationProvider";
109 private static final String FUSED_LOCATION_SERVICE_ACTION =
110 "com.android.location.service.FusedLocationProvider";
111
112 private static final int MSG_LOCATION_CHANGED = 1;
113
Nick Pellyf1be6862012-05-15 10:53:42 -0700114 // Location Providers may sometimes deliver location updates
115 // slightly faster that requested - provide grace period so
116 // we don't unnecessarily filter events that are otherwise on
117 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700118 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700119
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700120 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
121
122 private final Context mContext;
123
124 // used internally for synchronization
125 private final Object mLock = new Object();
126
127 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700128 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700129 private GeofenceManager mGeofenceManager;
130 private PowerManager.WakeLock mWakeLock;
131 private PackageManager mPackageManager;
132 private GeocoderProxy mGeocodeProvider;
133 private IGpsStatusProvider mGpsStatusProvider;
134 private INetInitiatedListener mNetInitiatedListener;
135 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700136 private PassiveProvider mPassiveProvider; // track passive provider for special cases
137 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700138
139 // --- fields below are protected by mWakeLock ---
140 private int mPendingBroadcasts;
141
142 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 // Set of providers that are explicitly enabled
144 private final Set<String> mEnabledProviders = new HashSet<String>();
145
146 // Set of providers that are explicitly disabled
147 private final Set<String> mDisabledProviders = new HashSet<String>();
148
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700149 // Mock (test) providers
150 private final HashMap<String, MockProvider> mMockProviders =
151 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700153 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400154 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700156 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500157 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700158 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400159
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160 // real providers, saved here when mocked out
161 private final HashMap<String, LocationProviderInterface> mRealProviders =
162 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700164 // mapping from provider name to provider
165 private final HashMap<String, LocationProviderInterface> mProvidersByName =
166 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700168 // mapping from provider name to all its UpdateRecords
169 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
170 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700171
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172 // mapping from provider name to last known location
173 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700175 // all providers that operate over proxy, for authorizing incoming location
176 private final ArrayList<LocationProviderProxy> mProxyProviders =
177 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
Victoria Lease38389b62012-09-30 11:44:22 -0700179 // current active user on the device - other users are denied location data
180 private int mCurrentUserId = UserHandle.USER_OWNER;
181
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700182 public LocationManagerService(Context context) {
183 super();
184 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800185
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700186 if (D) Log.d(TAG, "Constructed");
187
188 // most startup is deferred until systemReady()
189 }
190
191 public void systemReady() {
192 Thread thread = new Thread(null, this, THREAD_NAME);
193 thread.start();
194 }
195
196 @Override
197 public void run() {
198 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
199 Looper.prepare();
200 mLocationHandler = new LocationWorkerHandler();
201 init();
202 Looper.loop();
203 }
204
205 private void init() {
206 if (D) Log.d(TAG, "init()");
207
208 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
209 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
210 mPackageManager = mContext.getPackageManager();
211
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700212 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
213 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700214 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700215
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700216 synchronized (mLock) {
217 loadProvidersLocked();
218 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700219
Nick Pelly4035f5a2012-08-17 14:43:49 -0700220 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700221
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700222 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700223 mContext.getContentResolver().registerContentObserver(
224 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
225 new ContentObserver(mLocationHandler) {
226 @Override
227 public void onChange(boolean selfChange) {
228 synchronized (mLock) {
229 updateProvidersLocked();
230 }
231 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700232 }, UserHandle.USER_ALL);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700233 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700234
Victoria Lease38389b62012-09-30 11:44:22 -0700235 // listen for user change
236 IntentFilter intentFilter = new IntentFilter();
237 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
238
239 mContext.registerReceiverAsUser(new BroadcastReceiver() {
240 @Override
241 public void onReceive(Context context, Intent intent) {
242 String action = intent.getAction();
243 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
244 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
245 }
246 }
247 }, UserHandle.ALL, intentFilter, null, null);
248
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700249 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700250 }
251
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500252 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
253 PackageManager pm = mContext.getPackageManager();
254 String systemPackageName = mContext.getPackageName();
255 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
256
257 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
258 new Intent(FUSED_LOCATION_SERVICE_ACTION),
259 PackageManager.GET_META_DATA, mCurrentUserId);
260 for (ResolveInfo rInfo : rInfos) {
261 String packageName = rInfo.serviceInfo.packageName;
262
263 // Check that the signature is in the list of supported sigs. If it's not in
264 // this list the standard provider binding logic won't bind to it.
265 try {
266 PackageInfo pInfo;
267 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
268 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
269 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
270 ", but has wrong signature, ignoring");
271 continue;
272 }
273 } catch (NameNotFoundException e) {
274 Log.e(TAG, "missing package: " + packageName);
275 continue;
276 }
277
278 // Get the version info
279 if (rInfo.serviceInfo.metaData == null) {
280 Log.w(TAG, "Found fused provider without metadata: " + packageName);
281 continue;
282 }
283
284 int version = rInfo.serviceInfo.metaData.getInt(
285 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
286 if (version == 0) {
287 // This should be the fallback fused location provider.
288
289 // Make sure it's in the system partition.
290 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
291 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
292 continue;
293 }
294
295 // Check that the fallback is signed the same as the OS
296 // as a proxy for coreApp="true"
297 if (pm.checkSignatures(systemPackageName, packageName)
298 != PackageManager.SIGNATURE_MATCH) {
299 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
300 + packageName);
301 continue;
302 }
303
304 // Found a valid fallback.
305 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
306 return;
307 } else {
308 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
309 }
310 }
311
312 throw new IllegalStateException("Unable to find a fused location provider that is in the "
313 + "system partition with version 0 and signed with the platform certificate. "
314 + "Such a package is needed to provide a default fused location provider in the "
315 + "event that no other fused location provider has been installed or is currently "
316 + "available. For example, coreOnly boot mode when decrypting the data "
317 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
318 }
319
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700320 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700321 // create a passive location provider, which is always enabled
322 PassiveProvider passiveProvider = new PassiveProvider(this);
323 addProviderLocked(passiveProvider);
324 mEnabledProviders.add(passiveProvider.getName());
325 mPassiveProvider = passiveProvider;
326
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700327 if (GpsLocationProvider.isSupported()) {
328 // Create a gps location provider
329 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
330 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
331 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
332 addProviderLocked(gpsProvider);
333 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
334 }
335
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700336 /*
337 Load package name(s) containing location provider support.
338 These packages can contain services implementing location providers:
339 Geocoder Provider, Network Location Provider, and
340 Fused Location Provider. They will each be searched for
341 service components implementing these providers.
342 The location framework also has support for installation
343 of new location providers at run-time. The new package does not
344 have to be explicitly listed here, however it must have a signature
345 that matches the signature of at least one package on this list.
346 */
347 Resources resources = mContext.getResources();
348 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500349 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700350 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500351 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
352 Arrays.toString(pkgs));
353 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
354
355 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700356
357 // bind to network provider
358 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
359 mContext,
360 LocationManager.NETWORK_PROVIDER,
361 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700362 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700363 if (networkProvider != null) {
364 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
365 mProxyProviders.add(networkProvider);
366 addProviderLocked(networkProvider);
367 } else {
368 Slog.w(TAG, "no network location provider found");
369 }
370
371 // bind to fused provider
372 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
373 mContext,
374 LocationManager.FUSED_PROVIDER,
375 FUSED_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700376 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700377 if (fusedLocationProvider != null) {
378 addProviderLocked(fusedLocationProvider);
379 mProxyProviders.add(fusedLocationProvider);
380 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700381 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700382 } else {
383 Slog.e(TAG, "no fused location provider found",
384 new IllegalStateException("Location service needs a fused location provider"));
385 }
386
387 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700388 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
389 mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700390 if (mGeocodeProvider == null) {
391 Slog.e(TAG, "no geocoder provider found");
392 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700393 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700396 * Called when the device's active user changes.
397 * @param userId the new active user's UserId
398 */
399 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700400 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700401 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700402 mLastLocation.clear();
403 for (LocationProviderInterface p : mProviders) {
404 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
405 p.switchUser(userId);
406 }
Victoria Lease38389b62012-09-30 11:44:22 -0700407 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700408 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700409 }
410 }
411
412 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
414 * location updates.
415 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700416 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700417 final int mUid; // uid of receiver
418 final int mPid; // pid of receiver
419 final String mPackageName; // package name of receiver
420 final String mPermission; // best permission that receiver has
421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 final ILocationListener mListener;
423 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700425
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400426 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700427
Mike Lockwood48f17512009-04-23 09:12:08 -0700428 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700430 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
431 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700434 if (listener != null) {
435 mKey = listener.asBinder();
436 } else {
437 mKey = intent;
438 }
439 mPermission = checkPermission();
440 mUid = uid;
441 mPid = pid;
442 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 }
444
445 @Override
446 public boolean equals(Object otherObj) {
447 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700448 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 }
450 return false;
451 }
452
453 @Override
454 public int hashCode() {
455 return mKey.hashCode();
456 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 @Override
459 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700460 StringBuilder s = new StringBuilder();
461 s.append("Reciever[");
462 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700464 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700466 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700468 for (String p : mUpdateRecords.keySet()) {
469 s.append(" ").append(mUpdateRecords.get(p).toString());
470 }
471 s.append("]");
472 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 }
474
475 public boolean isListener() {
476 return mListener != null;
477 }
478
479 public boolean isPendingIntent() {
480 return mPendingIntent != null;
481 }
482
483 public ILocationListener getListener() {
484 if (mListener != null) {
485 return mListener;
486 }
487 throw new IllegalStateException("Request for non-existent listener");
488 }
489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
491 if (mListener != null) {
492 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700493 synchronized (this) {
494 // synchronize to ensure incrementPendingBroadcastsLocked()
495 // is called before decrementPendingBroadcasts()
496 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700497 // call this after broadcasting so we do not increment
498 // if we throw an exeption.
499 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700500 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 } catch (RemoteException e) {
502 return false;
503 }
504 } else {
505 Intent statusChanged = new Intent();
506 statusChanged.putExtras(extras);
507 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
508 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700509 synchronized (this) {
510 // synchronize to ensure incrementPendingBroadcastsLocked()
511 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700512 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700513 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700514 // call this after broadcasting so we do not increment
515 // if we throw an exeption.
516 incrementPendingBroadcastsLocked();
517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 } catch (PendingIntent.CanceledException e) {
519 return false;
520 }
521 }
522 return true;
523 }
524
525 public boolean callLocationChangedLocked(Location location) {
526 if (mListener != null) {
527 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700528 synchronized (this) {
529 // synchronize to ensure incrementPendingBroadcastsLocked()
530 // is called before decrementPendingBroadcasts()
531 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700532 // call this after broadcasting so we do not increment
533 // if we throw an exeption.
534 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700535 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 } catch (RemoteException e) {
537 return false;
538 }
539 } else {
540 Intent locationChanged = new Intent();
541 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
542 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700543 synchronized (this) {
544 // synchronize to ensure incrementPendingBroadcastsLocked()
545 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700546 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700547 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700548 // call this after broadcasting so we do not increment
549 // if we throw an exeption.
550 incrementPendingBroadcastsLocked();
551 }
552 } catch (PendingIntent.CanceledException e) {
553 return false;
554 }
555 }
556 return true;
557 }
558
559 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
560 if (mListener != null) {
561 try {
562 synchronized (this) {
563 // synchronize to ensure incrementPendingBroadcastsLocked()
564 // is called before decrementPendingBroadcasts()
565 if (enabled) {
566 mListener.onProviderEnabled(provider);
567 } else {
568 mListener.onProviderDisabled(provider);
569 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700570 // call this after broadcasting so we do not increment
571 // if we throw an exeption.
572 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700573 }
574 } catch (RemoteException e) {
575 return false;
576 }
577 } else {
578 Intent providerIntent = new Intent();
579 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
580 try {
581 synchronized (this) {
582 // synchronize to ensure incrementPendingBroadcastsLocked()
583 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700584 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700585 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700586 // call this after broadcasting so we do not increment
587 // if we throw an exeption.
588 incrementPendingBroadcastsLocked();
589 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 } catch (PendingIntent.CanceledException e) {
591 return false;
592 }
593 }
594 return true;
595 }
596
Nick Pellyf1be6862012-05-15 10:53:42 -0700597 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700599 if (D) Log.d(TAG, "Location listener died");
600
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400601 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 removeUpdatesLocked(this);
603 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700604 synchronized (this) {
605 if (mPendingBroadcasts > 0) {
606 LocationManagerService.this.decrementPendingBroadcasts();
607 mPendingBroadcasts = 0;
608 }
609 }
610 }
611
Nick Pellye0fd6932012-07-11 10:26:13 -0700612 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700613 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
614 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400615 synchronized (this) {
616 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700617 }
618 }
619
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400620 // this must be called while synchronized by caller in a synchronized block
621 // containing the sending of the broadcaset
622 private void incrementPendingBroadcastsLocked() {
623 if (mPendingBroadcasts++ == 0) {
624 LocationManagerService.this.incrementPendingBroadcasts();
625 }
626 }
627
628 private void decrementPendingBroadcastsLocked() {
629 if (--mPendingBroadcasts == 0) {
630 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700631 }
632 }
633 }
634
Nick Pellye0fd6932012-07-11 10:26:13 -0700635 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700636 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400637 //Do not use getReceiver here as that will add the ILocationListener to
638 //the receiver list if it is not found. If it is not found then the
639 //LocationListener was removed when it had a pending broadcast and should
640 //not be added back.
641 IBinder binder = listener.asBinder();
642 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700643 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400644 synchronized (receiver) {
645 // so wakelock calls will succeed
646 long identity = Binder.clearCallingIdentity();
647 receiver.decrementPendingBroadcastsLocked();
648 Binder.restoreCallingIdentity(identity);
649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 }
651 }
652
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700653 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400654 mProviders.add(provider);
655 mProvidersByName.put(provider.getName(), provider);
656 }
657
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700658 private void removeProviderLocked(LocationProviderInterface provider) {
659 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400660 mProviders.remove(provider);
661 mProvidersByName.remove(provider.getName());
662 }
663
Mike Lockwood3d12b512009-04-21 23:25:35 -0700664
Victoria Leaseb711d572012-10-02 13:14:11 -0700665 private boolean isAllowedBySettingsLocked(String provider, int userId) {
666 if (userId != mCurrentUserId) {
667 return false;
668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 if (mEnabledProviders.contains(provider)) {
670 return true;
671 }
672 if (mDisabledProviders.contains(provider)) {
673 return false;
674 }
675 // Use system settings
676 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677
Victoria Leaseb711d572012-10-02 13:14:11 -0700678 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 }
680
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700681 /**
Victoria Leaseda479c52012-10-15 15:24:16 -0700682 * Returns the best permission available to the caller.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700683 */
Victoria Leaseda479c52012-10-15 15:24:16 -0700684 private String getBestCallingPermission() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700685 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
686 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700687 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700688 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
689 PackageManager.PERMISSION_GRANTED) {
690 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700692 return null;
693 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700694
Victoria Leaseda479c52012-10-15 15:24:16 -0700695 /**
696 * Throw SecurityException if caller has neither COARSE or FINE.
697 * Otherwise, return the best permission.
698 */
699 private String checkPermission() {
700 String perm = getBestCallingPermission();
701 if (perm == null) {
702 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
703 " ACCESS_FINE_LOCATION permission");
704 }
705 return perm;
Victoria Lease4fab68b2012-09-13 13:20:59 -0700706 }
707
708 /**
709 * Throw SecurityException if caller lacks permission to use Geofences.
710 */
711 private void checkGeofencePermission() {
712 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
713 PackageManager.PERMISSION_GRANTED) {
714 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
715 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 }
717
Victoria Leaseda479c52012-10-15 15:24:16 -0700718 private String getMinimumPermissionForProvider(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700719 if (LocationManager.GPS_PROVIDER.equals(provider) ||
720 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
721 // gps and passive providers require FINE permission
Victoria Leaseda479c52012-10-15 15:24:16 -0700722 return ACCESS_FINE_LOCATION;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700723 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
724 LocationManager.FUSED_PROVIDER.equals(provider)) {
725 // network and fused providers are ok with COARSE or FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700726 return ACCESS_COARSE_LOCATION;
Laurent Tu941221c2012-10-04 14:21:52 -0700727 } else {
728 // mock providers
729 LocationProviderInterface lp = mMockProviders.get(provider);
730 if (lp != null) {
731 ProviderProperties properties = lp.getProperties();
732 if (properties != null) {
733 if (properties.mRequiresSatellite) {
734 // provider requiring satellites require FINE permission
Victoria Leaseda479c52012-10-15 15:24:16 -0700735 return ACCESS_FINE_LOCATION;
Laurent Tu941221c2012-10-04 14:21:52 -0700736 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
737 // provider requiring network and or cell require COARSE or FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700738 return ACCESS_COARSE_LOCATION;
Laurent Tu941221c2012-10-04 14:21:52 -0700739 }
740 }
741 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700742 }
Laurent Tu941221c2012-10-04 14:21:52 -0700743
Victoria Leaseda479c52012-10-15 15:24:16 -0700744 return null;
745 }
746
747 private boolean isPermissionSufficient(String perm, String minPerm) {
748 if (ACCESS_FINE_LOCATION.equals(minPerm)) {
749 return ACCESS_FINE_LOCATION.equals(perm);
750 } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) {
751 return ACCESS_FINE_LOCATION.equals(perm) ||
752 ACCESS_COARSE_LOCATION.equals(perm);
753 } else {
754 return false;
755 }
756 }
757
758 private void checkPermissionForProvider(String perm, String provider) {
759 String minPerm = getMinimumPermissionForProvider(provider);
760 if (!isPermissionSufficient(perm, minPerm)) {
761 if (ACCESS_FINE_LOCATION.equals(minPerm)) {
762 throw new SecurityException("Location provider \"" + provider +
763 "\" requires ACCESS_FINE_LOCATION permission.");
764 } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) {
765 throw new SecurityException("Location provider \"" + provider +
766 "\" requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
767 } else {
768 throw new SecurityException("Insufficient permission for location provider \"" +
769 provider + "\".");
770 }
771 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700772 }
773
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700774 /**
775 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700776 * fused, also including ones that are not permitted to
777 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700778 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700779 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700781 ArrayList<String> out;
782 synchronized (mLock) {
783 out = new ArrayList<String>(mProviders.size());
784 for (LocationProviderInterface provider : mProviders) {
785 String name = provider.getName();
786 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700787 continue;
788 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 out.add(name);
790 }
791 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700792
793 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 return out;
795 }
796
Mike Lockwood03ca2162010-04-01 08:10:09 -0700797 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700798 * Return all providers by name, that match criteria and are optionally
799 * enabled.
800 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700801 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700802 @Override
803 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700804 ArrayList<String> out;
Victoria Leaseda479c52012-10-15 15:24:16 -0700805 String perm = getBestCallingPermission();
Victoria Leaseb711d572012-10-02 13:14:11 -0700806 int callingUserId = UserHandle.getCallingUserId();
807 long identity = Binder.clearCallingIdentity();
808 try {
809 synchronized (mLock) {
810 out = new ArrayList<String>(mProviders.size());
811 for (LocationProviderInterface provider : mProviders) {
812 String name = provider.getName();
813 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700814 continue;
815 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700816 if (isPermissionSufficient(perm, getMinimumPermissionForProvider(name))) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700817 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
818 continue;
819 }
820 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
821 name, provider.getProperties(), criteria)) {
822 continue;
823 }
824 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700825 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700826 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700827 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700828 } finally {
829 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700830 }
831
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700832 if (D) Log.d(TAG, "getProviders()=" + out);
833 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700834 }
835
836 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700837 * Return the name of the best provider given a Criteria object.
838 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700839 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700840 * has been deprecated as well. So this method now uses
841 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700842 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700843 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700844 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700845 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700846
847 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700848 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700849 result = pickBest(providers);
850 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
851 return result;
852 }
853 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700854 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700855 result = pickBest(providers);
856 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
857 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700858 }
859
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700860 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700861 return null;
862 }
863
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700864 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700865 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700866 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700867 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
868 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700869 } else {
870 return providers.get(0);
871 }
872 }
873
Nick Pellye0fd6932012-07-11 10:26:13 -0700874 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700875 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700876 checkPermission();
877
Mike Lockwood03ca2162010-04-01 08:10:09 -0700878 LocationProviderInterface p = mProvidersByName.get(provider);
879 if (p == null) {
880 throw new IllegalArgumentException("provider=" + provider);
881 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700882
883 boolean result = LocationProvider.propertiesMeetCriteria(
884 p.getName(), p.getProperties(), criteria);
885 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
886 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700887 }
888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700890 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400891 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500892 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 boolean isEnabled = p.isEnabled();
894 String name = p.getName();
Victoria Leaseb711d572012-10-02 13:14:11 -0700895 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700897 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700898 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700900 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700901 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700903 }
904 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700905 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
906 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907 }
908 }
909
Victoria Leaseb711d572012-10-02 13:14:11 -0700910 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 int listeners = 0;
912
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500913 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700914 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915
916 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
919 if (records != null) {
920 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700921 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 UpdateRecord record = records.get(i);
Victoria Leaseb711d572012-10-02 13:14:11 -0700923 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
924 // Sends a notification message to the receiver
925 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
926 if (deadReceivers == null) {
927 deadReceivers = new ArrayList<Receiver>();
928 }
929 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700931 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 }
934 }
935
936 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700937 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 removeUpdatesLocked(deadReceivers.get(i));
939 }
940 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 if (enabled) {
943 p.enable();
944 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700945 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 }
947 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 }
951
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700952 private void applyRequirementsLocked(String provider) {
953 LocationProviderInterface p = mProvidersByName.get(provider);
954 if (p == null) return;
955
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700957 WorkSource worksource = new WorkSource();
958 ProviderRequest providerRequest = new ProviderRequest();
959
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700961 for (UpdateRecord record : records) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700962 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
963 LocationRequest locationRequest = record.mRequest;
964 providerRequest.locationRequests.add(locationRequest);
965 if (locationRequest.getInterval() < providerRequest.interval) {
966 providerRequest.reportLocation = true;
967 providerRequest.interval = locationRequest.getInterval();
968 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700969 }
970 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700971
972 if (providerRequest.reportLocation) {
973 // calculate who to blame for power
974 // This is somewhat arbitrary. We pick a threshold interval
975 // that is slightly higher that the minimum interval, and
976 // spread the blame across all applications with a request
977 // under that threshold.
978 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
979 for (UpdateRecord record : records) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700980 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
981 LocationRequest locationRequest = record.mRequest;
982 if (locationRequest.getInterval() <= thresholdInterval) {
983 worksource.add(record.mReceiver.mUid);
984 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700985 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700986 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 }
988 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700989
990 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
991 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 }
993
994 private class UpdateRecord {
995 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700996 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400998 Location mLastFixBroadcast;
999 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000
1001 /**
1002 * Note: must be constructed with lock held.
1003 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001004 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001006 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008
1009 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1010 if (records == null) {
1011 records = new ArrayList<UpdateRecord>();
1012 mRecordsByProvider.put(provider, records);
1013 }
1014 if (!records.contains(this)) {
1015 records.add(this);
1016 }
1017 }
1018
1019 /**
1020 * Method to be called when a record will no longer be used. Calling this multiple times
1021 * must have the same effect as calling it once.
1022 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001023 void disposeLocked(boolean removeReceiver) {
1024 // remove from mRecordsByProvider
1025 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1026 if (globalRecords != null) {
1027 globalRecords.remove(this);
1028 }
1029
1030 if (!removeReceiver) return; // the caller will handle the rest
1031
1032 // remove from Receiver#mUpdateRecords
1033 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1034 if (receiverRecords != null) {
1035 receiverRecords.remove(this.mProvider);
1036
1037 // and also remove the Receiver if it has no more update records
1038 if (removeReceiver && receiverRecords.size() == 0) {
1039 removeUpdatesLocked(mReceiver);
1040 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001041 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 }
1043
1044 @Override
1045 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001046 StringBuilder s = new StringBuilder();
1047 s.append("UpdateRecord[");
1048 s.append(mProvider);
1049 s.append(' ').append(mReceiver.mPackageName).append('(');
1050 s.append(mReceiver.mUid).append(')');
1051 s.append(' ').append(mRequest);
1052 s.append(']');
1053 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 }
1056
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001057 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001058 IBinder binder = listener.asBinder();
1059 Receiver receiver = mReceivers.get(binder);
1060 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001061 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001062 mReceivers.put(binder, receiver);
1063
1064 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001065 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001066 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001067 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001068 return null;
1069 }
1070 }
1071 return receiver;
1072 }
1073
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001074 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001075 Receiver receiver = mReceivers.get(intent);
1076 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001077 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001078 mReceivers.put(intent, receiver);
1079 }
1080 return receiver;
1081 }
1082
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001083 private String checkPermissionAndRequest(LocationRequest request) {
Victoria Leaseda479c52012-10-15 15:24:16 -07001084 String perm = getBestCallingPermission();
1085 String provider = request.getProvider();
1086 checkPermissionForProvider(perm, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001087
1088 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001089 switch (request.getQuality()) {
1090 case LocationRequest.ACCURACY_FINE:
1091 request.setQuality(LocationRequest.ACCURACY_BLOCK);
1092 break;
1093 case LocationRequest.POWER_HIGH:
1094 request.setQuality(LocationRequest.POWER_LOW);
1095 break;
1096 }
1097 // throttle
1098 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1099 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1100 }
1101 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1102 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1103 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001104 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001105 // make getFastestInterval() the minimum of interval and fastest interval
1106 if (request.getFastestInterval() > request.getInterval()) {
1107 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001108 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001109 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001110 }
1111
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001112 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001113 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001114 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001115 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001116 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001117 String[] packages = mPackageManager.getPackagesForUid(uid);
1118 if (packages == null) {
1119 throw new SecurityException("invalid UID " + uid);
1120 }
1121 for (String pkg : packages) {
1122 if (packageName.equals(pkg)) return;
1123 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001124 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001125 }
1126
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001127 private void checkPendingIntent(PendingIntent intent) {
1128 if (intent == null) {
1129 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001130 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001131 }
1132
1133 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1134 int pid, int uid, String packageName) {
1135 if (intent == null && listener == null) {
1136 throw new IllegalArgumentException("need eiter listener or intent");
1137 } else if (intent != null && listener != null) {
1138 throw new IllegalArgumentException("cannot register both listener and intent");
1139 } else if (intent != null) {
1140 checkPendingIntent(intent);
1141 return getReceiver(intent, pid, uid, packageName);
1142 } else {
1143 return getReceiver(listener, pid, uid, packageName);
1144 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001145 }
1146
Nick Pellye0fd6932012-07-11 10:26:13 -07001147 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001148 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1149 PendingIntent intent, String packageName) {
1150 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1151 checkPackageName(packageName);
1152 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001154 final int pid = Binder.getCallingPid();
1155 final int uid = Binder.getCallingUid();
1156 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001158 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 long identity = Binder.clearCallingIdentity();
1160 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001161 synchronized (mLock) {
1162 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 } finally {
1165 Binder.restoreCallingIdentity(identity);
1166 }
1167 }
1168
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001169 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1170 int pid, int uid, String packageName) {
1171 // Figure out the provider. Either its explicitly request (legacy use cases), or
1172 // use the fused provider
1173 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1174 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001175 if (name == null) {
1176 throw new IllegalArgumentException("provider name must not be null");
1177 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001178 LocationProviderInterface provider = mProvidersByName.get(name);
1179 if (provider == null) {
1180 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1181 }
1182
1183 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1184 name + " " + request + " from " + packageName + "(" + uid + ")");
1185
1186 UpdateRecord record = new UpdateRecord(name, request, receiver);
1187 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1188 if (oldRecord != null) {
1189 oldRecord.disposeLocked(false);
1190 }
1191
Victoria Leaseb711d572012-10-02 13:14:11 -07001192 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001193 if (isProviderEnabled) {
1194 applyRequirementsLocked(name);
1195 } else {
1196 // Notify the listener that updates are currently disabled
1197 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 }
1199 }
1200
Nick Pellye0fd6932012-07-11 10:26:13 -07001201 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001202 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1203 String packageName) {
1204 checkPackageName(packageName);
1205 checkPermission();
1206 final int pid = Binder.getCallingPid();
1207 final int uid = Binder.getCallingUid();
1208 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1209
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001210 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001211 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001213 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001214 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001216 } finally {
1217 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 }
1219 }
1220
1221 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1223
1224 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1225 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1226 synchronized (receiver) {
1227 if (receiver.mPendingBroadcasts > 0) {
1228 decrementPendingBroadcasts();
1229 receiver.mPendingBroadcasts = 0;
1230 }
1231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 }
1233
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001234 // Record which providers were associated with this listener
1235 HashSet<String> providers = new HashSet<String>();
1236 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1237 if (oldRecords != null) {
1238 // Call dispose() on the obsolete update records.
1239 for (UpdateRecord record : oldRecords.values()) {
1240 record.disposeLocked(false);
1241 }
1242 // Accumulate providers
1243 providers.addAll(oldRecords.keySet());
1244 }
1245
1246 // update provider
1247 for (String provider : providers) {
1248 // If provider is already disabled, don't need to do anything
Victoria Leaseb711d572012-10-02 13:14:11 -07001249 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001250 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 }
1252
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001253 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 }
1255 }
1256
Nick Pellye0fd6932012-07-11 10:26:13 -07001257 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001258 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001259 if (D) Log.d(TAG, "getLastLocation: " + request);
1260 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1261 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001262 checkPackageName(packageName);
1263
Victoria Leaseb711d572012-10-02 13:14:11 -07001264 long identity = Binder.clearCallingIdentity();
1265 try {
1266 if (mBlacklist.isBlacklisted(packageName)) {
1267 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1268 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001269 return null;
1270 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001271
1272 synchronized (mLock) {
1273 // Figure out the provider. Either its explicitly request (deprecated API's),
1274 // or use the fused provider
1275 String name = request.getProvider();
1276 if (name == null) name = LocationManager.FUSED_PROVIDER;
1277 LocationProviderInterface provider = mProvidersByName.get(name);
1278 if (provider == null) return null;
1279
1280 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
1281
1282 Location location = mLastLocation.get(name);
1283 if (location == null) {
1284 return null;
1285 }
1286 if (ACCESS_FINE_LOCATION.equals(perm)) {
1287 return location;
1288 } else {
1289 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1290 if (noGPSLocation != null) {
1291 return mLocationFudger.getOrCreate(noGPSLocation);
1292 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001293 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001294 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001295 return null;
1296 } finally {
1297 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001298 }
1299 }
1300
1301 @Override
1302 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1303 String packageName) {
1304 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001305 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001306 checkPermissionAndRequest(request);
1307 checkPendingIntent(intent);
1308 checkPackageName(packageName);
1309
1310 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1311
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001312 // geo-fence manager uses the public location API, need to clear identity
1313 int uid = Binder.getCallingUid();
1314 long identity = Binder.clearCallingIdentity();
1315 try {
1316 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1317 } finally {
1318 Binder.restoreCallingIdentity(identity);
1319 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001320 }
1321
1322 @Override
1323 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001324 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001325 checkPendingIntent(intent);
1326 checkPackageName(packageName);
1327
1328 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1329
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001330 // geo-fence manager uses the public location API, need to clear identity
1331 long identity = Binder.clearCallingIdentity();
1332 try {
1333 mGeofenceManager.removeFence(geofence, intent);
1334 } finally {
1335 Binder.restoreCallingIdentity(identity);
1336 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001337 }
1338
1339
1340 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001342 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 return false;
1344 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001345 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 PackageManager.PERMISSION_GRANTED) {
1347 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1348 }
1349
1350 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001351 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001353 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 return false;
1355 }
1356 return true;
1357 }
1358
Nick Pellye0fd6932012-07-11 10:26:13 -07001359 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001361 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001362 try {
1363 mGpsStatusProvider.removeGpsStatusListener(listener);
1364 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001365 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 }
1368 }
1369
Nick Pellye0fd6932012-07-11 10:26:13 -07001370 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001372 if (provider == null) {
1373 // throw NullPointerException to remain compatible with previous implementation
1374 throw new NullPointerException();
1375 }
1376
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001377 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001379 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001380 != PackageManager.PERMISSION_GRANTED)) {
1381 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1382 }
1383
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001384 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001385 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001386 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001387
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001388 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 }
1390 }
1391
Nick Pellye0fd6932012-07-11 10:26:13 -07001392 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001393 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001394 if (Binder.getCallingUid() != Process.myUid()) {
1395 throw new SecurityException(
1396 "calling sendNiResponse from outside of the system is not allowed");
1397 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001398 try {
1399 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001400 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001401 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001402 return false;
1403 }
1404 }
1405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001407 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001408 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 * accessed by the caller
1410 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001411 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001412 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001413 if (mProvidersByName.get(provider) == null) {
1414 return null;
1415 }
1416
Victoria Leaseda479c52012-10-15 15:24:16 -07001417 checkPermissionForProvider(getBestCallingPermission(), provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001419 LocationProviderInterface p;
1420 synchronized (mLock) {
1421 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 }
1423
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001424 if (p == null) return null;
1425 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 }
1427
Nick Pellye0fd6932012-07-11 10:26:13 -07001428 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 public boolean isProviderEnabled(String provider) {
Victoria Leaseda479c52012-10-15 15:24:16 -07001430 checkPermissionForProvider(getBestCallingPermission(), provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001431 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1432
Victoria Leaseb711d572012-10-02 13:14:11 -07001433 long identity = Binder.clearCallingIdentity();
1434 try {
1435 synchronized (mLock) {
1436 LocationProviderInterface p = mProvidersByName.get(provider);
1437 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001438
Victoria Leaseb711d572012-10-02 13:14:11 -07001439 return isAllowedBySettingsLocked(provider, mCurrentUserId);
1440 }
1441 } finally {
1442 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001443 }
1444 }
1445
1446 private void checkCallerIsProvider() {
1447 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1448 == PackageManager.PERMISSION_GRANTED) {
1449 return;
1450 }
1451
1452 // Previously we only used the INSTALL_LOCATION_PROVIDER
1453 // check. But that is system or signature
1454 // protection level which is not flexible enough for
1455 // providers installed oustide the system image. So
1456 // also allow providers with a UID matching the
1457 // currently bound package name
1458
1459 int uid = Binder.getCallingUid();
1460
1461 if (mGeocodeProvider != null) {
1462 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1463 }
1464 for (LocationProviderProxy proxy : mProxyProviders) {
1465 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1466 }
1467 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1468 "or UID of a currently bound location provider");
1469 }
1470
1471 private boolean doesPackageHaveUid(int uid, String packageName) {
1472 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001473 return false;
1474 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001475 try {
1476 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1477 if (appInfo.uid != uid) {
1478 return false;
1479 }
1480 } catch (NameNotFoundException e) {
1481 return false;
1482 }
1483 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001484 }
1485
Nick Pellye0fd6932012-07-11 10:26:13 -07001486 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001487 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001488 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001489
Nick Pelly2eeeec22012-07-18 13:13:37 -07001490 if (!location.isComplete()) {
1491 Log.w(TAG, "Dropping incomplete location: " + location);
1492 return;
1493 }
1494
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001495 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1496 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001497 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001498 mLocationHandler.sendMessageAtFrontOfQueue(m);
1499 }
1500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501
1502 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1503 // Always broadcast the first update
1504 if (lastLoc == null) {
1505 return true;
1506 }
1507
Nick Pellyf1be6862012-05-15 10:53:42 -07001508 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001509 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001510 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001511 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 return false;
1513 }
1514
1515 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001516 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 if (minDistance > 0.0) {
1518 if (loc.distanceTo(lastLoc) <= minDistance) {
1519 return false;
1520 }
1521 }
1522
1523 return true;
1524 }
1525
Mike Lockwooda4903f22010-02-17 06:42:23 -05001526 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001527 if (D) Log.d(TAG, "incoming location: " + location);
1528
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001529 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001530 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531
Laurent Tu60ec50a2012-10-04 17:00:10 -07001532 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001533 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001534 if (p == null) return;
1535
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001536 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001537 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1538 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001539 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001540 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001541 lastLocation = new Location(provider);
1542 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001543 } else {
1544 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1545 if (noGPSLocation == null && lastNoGPSLocation != null) {
1546 // New location has no no-GPS location: adopt last no-GPS location. This is set
1547 // directly into location because we do not want to notify COARSE clients.
1548 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1549 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001550 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001551 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552
Laurent Tu60ec50a2012-10-04 17:00:10 -07001553 // Skip if there are no UpdateRecords for this provider.
1554 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1555 if (records == null || records.size() == 0) return;
1556
Victoria Lease09016ab2012-09-16 12:33:15 -07001557 // Fetch coarse location
1558 Location coarseLocation = null;
1559 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1560 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1561 }
1562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 // Fetch latest status update time
1564 long newStatusUpdateTime = p.getStatusUpdateTime();
1565
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001566 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 Bundle extras = new Bundle();
1568 int status = p.getStatus(extras);
1569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001571 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001574 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001576 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001577
Victoria Leaseb711d572012-10-02 13:14:11 -07001578 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1579 if (receiverUserId != mCurrentUserId) {
1580 if (D) {
1581 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
1582 " (current user: " + mCurrentUserId + ", app: " +
1583 receiver.mPackageName + ")");
1584 }
1585 continue;
1586 }
1587
Nick Pelly4035f5a2012-08-17 14:43:49 -07001588 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1589 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1590 receiver.mPackageName);
1591 continue;
1592 }
1593
Victoria Lease09016ab2012-09-16 12:33:15 -07001594 Location notifyLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001595 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001596 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001597 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001598 notifyLocation = coarseLocation; // use coarse location if available
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001599 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001600 if (notifyLocation != null) {
1601 Location lastLoc = r.mLastFixBroadcast;
1602 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1603 if (lastLoc == null) {
1604 lastLoc = new Location(notifyLocation);
1605 r.mLastFixBroadcast = lastLoc;
1606 } else {
1607 lastLoc.set(notifyLocation);
1608 }
1609 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1610 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1611 receiverDead = true;
1612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 }
1614 }
1615
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001616 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001618 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001620 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001622 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001623 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001624 }
1625 }
1626
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001627 // track expired records
1628 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1629 if (deadUpdateRecords == null) {
1630 deadUpdateRecords = new ArrayList<UpdateRecord>();
1631 }
1632 deadUpdateRecords.add(r);
1633 }
1634 // track dead receivers
1635 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001636 if (deadReceivers == null) {
1637 deadReceivers = new ArrayList<Receiver>();
1638 }
1639 if (!deadReceivers.contains(receiver)) {
1640 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641 }
1642 }
1643 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001644
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001645 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001647 for (Receiver receiver : deadReceivers) {
1648 removeUpdatesLocked(receiver);
1649 }
1650 }
1651 if (deadUpdateRecords != null) {
1652 for (UpdateRecord r : deadUpdateRecords) {
1653 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 }
1655 }
1656 }
1657
1658 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 @Override
1660 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001661 switch (msg.what) {
1662 case MSG_LOCATION_CHANGED:
1663 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1664 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 }
1666 }
1667 }
1668
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001669 private void handleLocationChanged(Location location, boolean passive) {
1670 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001671
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001672 if (!passive) {
1673 // notify passive provider of the new location
1674 mPassiveProvider.updateLocation(location);
1675 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001677 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001678 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001679 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683
Mike Lockwoode97ae402010-09-29 15:23:46 -04001684 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1685 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001686 public void onPackageDisappeared(String packageName, int reason) {
1687 // remove all receivers associated with this package name
1688 synchronized (mLock) {
1689 ArrayList<Receiver> deadReceivers = null;
1690
1691 for (Receiver receiver : mReceivers.values()) {
1692 if (receiver.mPackageName.equals(packageName)) {
1693 if (deadReceivers == null) {
1694 deadReceivers = new ArrayList<Receiver>();
1695 }
1696 deadReceivers.add(receiver);
1697 }
1698 }
1699
1700 // perform removal outside of mReceivers loop
1701 if (deadReceivers != null) {
1702 for (Receiver receiver : deadReceivers) {
1703 removeUpdatesLocked(receiver);
1704 }
1705 }
1706 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001707 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001708 };
1709
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 // Wake locks
1711
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001712 private void incrementPendingBroadcasts() {
1713 synchronized (mWakeLock) {
1714 if (mPendingBroadcasts++ == 0) {
1715 try {
1716 mWakeLock.acquire();
1717 log("Acquired wakelock");
1718 } catch (Exception e) {
1719 // This is to catch a runtime exception thrown when we try to release an
1720 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001721 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001722 }
1723 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001724 }
1725 }
1726
1727 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001728 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001729 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001730 try {
1731 // Release wake lock
1732 if (mWakeLock.isHeld()) {
1733 mWakeLock.release();
1734 log("Released wakelock");
1735 } else {
1736 log("Can't release wakelock again!");
1737 }
1738 } catch (Exception e) {
1739 // This is to catch a runtime exception thrown when we try to release an
1740 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001741 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001742 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001743 }
1744 }
1745 }
1746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 // Geocoder
1748
Nick Pellye0fd6932012-07-11 10:26:13 -07001749 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001750 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001751 return mGeocodeProvider != null;
1752 }
1753
Nick Pellye0fd6932012-07-11 10:26:13 -07001754 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001756 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001757 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001758 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1759 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001761 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 }
1763
Mike Lockwooda55c3212009-04-15 11:10:11 -04001764
Nick Pellye0fd6932012-07-11 10:26:13 -07001765 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001767 double lowerLeftLatitude, double lowerLeftLongitude,
1768 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001769 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001770
1771 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001772 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1773 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1774 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001776 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001777 }
1778
1779 // Mock Providers
1780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 private void checkMockPermissionsSafe() {
1782 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1783 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1784 if (!allowMocks) {
1785 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1786 }
1787
1788 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1789 PackageManager.PERMISSION_GRANTED) {
1790 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001791 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 }
1793
Nick Pellye0fd6932012-07-11 10:26:13 -07001794 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001795 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 checkMockPermissionsSafe();
1797
Mike Lockwooda4903f22010-02-17 06:42:23 -05001798 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1799 throw new IllegalArgumentException("Cannot mock the passive location provider");
1800 }
1801
Mike Lockwood86328a92009-10-23 08:38:25 -04001802 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001803 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001804 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001805 // remove the real provider if we are replacing GPS or network provider
1806 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001807 || LocationManager.NETWORK_PROVIDER.equals(name)
1808 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001809 LocationProviderInterface p = mProvidersByName.get(name);
1810 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001811 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001812 }
1813 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001814 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1816 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001817 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001818 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001819 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 updateProvidersLocked();
1821 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001822 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 }
1824
Nick Pellye0fd6932012-07-11 10:26:13 -07001825 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 public void removeTestProvider(String provider) {
1827 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001828 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001829 MockProvider mockProvider = mMockProviders.get(provider);
1830 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001831 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1832 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001833 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001834 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001835 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001836
1837 // reinstate real provider if available
1838 LocationProviderInterface realProvider = mRealProviders.get(provider);
1839 if (realProvider != null) {
1840 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001841 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001842 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001844 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 }
1846 }
1847
Nick Pellye0fd6932012-07-11 10:26:13 -07001848 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 public void setTestProviderLocation(String provider, Location loc) {
1850 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001851 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001852 MockProvider mockProvider = mMockProviders.get(provider);
1853 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1855 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001856 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1857 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001858 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001859 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860 }
1861 }
1862
Nick Pellye0fd6932012-07-11 10:26:13 -07001863 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 public void clearTestProviderLocation(String provider) {
1865 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001866 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001867 MockProvider mockProvider = mMockProviders.get(provider);
1868 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1870 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001871 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 }
1873 }
1874
Nick Pellye0fd6932012-07-11 10:26:13 -07001875 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 public void setTestProviderEnabled(String provider, boolean enabled) {
1877 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001878 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001879 MockProvider mockProvider = mMockProviders.get(provider);
1880 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1882 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001883 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001885 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 mEnabledProviders.add(provider);
1887 mDisabledProviders.remove(provider);
1888 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001889 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 mEnabledProviders.remove(provider);
1891 mDisabledProviders.add(provider);
1892 }
1893 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001894 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 }
1896 }
1897
Nick Pellye0fd6932012-07-11 10:26:13 -07001898 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 public void clearTestProviderEnabled(String provider) {
1900 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001901 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001902 MockProvider mockProvider = mMockProviders.get(provider);
1903 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1905 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001906 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001907 mEnabledProviders.remove(provider);
1908 mDisabledProviders.remove(provider);
1909 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001910 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 }
1912 }
1913
Nick Pellye0fd6932012-07-11 10:26:13 -07001914 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1916 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001917 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001918 MockProvider mockProvider = mMockProviders.get(provider);
1919 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1921 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001922 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 }
1924 }
1925
Nick Pellye0fd6932012-07-11 10:26:13 -07001926 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 public void clearTestProviderStatus(String provider) {
1928 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001929 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001930 MockProvider mockProvider = mMockProviders.get(provider);
1931 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001932 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1933 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001934 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001935 }
1936 }
1937
1938 private void log(String log) {
1939 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001940 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 }
1942 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001943
1944 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1946 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1947 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001948 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001949 + Binder.getCallingPid()
1950 + ", uid=" + Binder.getCallingUid());
1951 return;
1952 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001953
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001954 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001957 for (Receiver receiver : mReceivers.values()) {
1958 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001961 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1962 pw.println(" " + entry.getKey() + ":");
1963 for (UpdateRecord record : entry.getValue()) {
1964 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 }
1966 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001968 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1969 String provider = entry.getKey();
1970 Location location = entry.getValue();
1971 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001973
Nick Pellye0fd6932012-07-11 10:26:13 -07001974 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 if (mEnabledProviders.size() > 0) {
1977 pw.println(" Enabled Providers:");
1978 for (String i : mEnabledProviders) {
1979 pw.println(" " + i);
1980 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001981
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 }
1983 if (mDisabledProviders.size() > 0) {
1984 pw.println(" Disabled Providers:");
1985 for (String i : mDisabledProviders) {
1986 pw.println(" " + i);
1987 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001989 pw.append(" ");
1990 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 if (mMockProviders.size() > 0) {
1992 pw.println(" Mock Providers:");
1993 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001994 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001995 }
1996 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001997
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001998 pw.append(" fudger: ");
1999 mLocationFudger.dump(fd, pw, args);
2000
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002001 if (args.length > 0 && "short".equals(args[0])) {
2002 return;
2003 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002004 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002005 pw.print(provider.getName() + " Internal State");
2006 if (provider instanceof LocationProviderProxy) {
2007 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2008 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002009 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002010 pw.println(":");
2011 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002012 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 }
2014 }
2015}