blob: 37dee1980c5496881ca9cc16869e06f176a6dce6 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070020import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070024import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050026import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070028import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050029import android.content.pm.ResolveInfo;
30import android.content.pm.Signature;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050031import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070032import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070034import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050035import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070036import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040038import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.ILocationListener;
40import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040041import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.location.Location;
43import android.location.LocationManager;
44import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070045import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.Binder;
47import android.os.Bundle;
48import android.os.Handler;
49import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070050import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.Message;
52import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070053import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070055import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070056import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070057import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080060import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
Mike Lockwoode97ae402010-09-29 15:23:46 -040062import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070063import com.android.internal.location.ProviderProperties;
64import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040065import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070066import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040067import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070068import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070069import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040070import com.android.server.location.LocationProviderInterface;
71import com.android.server.location.LocationProviderProxy;
72import com.android.server.location.MockProvider;
73import com.android.server.location.PassiveProvider;
74
75import java.io.FileDescriptor;
76import java.io.PrintWriter;
77import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070078import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040079import java.util.HashMap;
80import java.util.HashSet;
81import java.util.List;
82import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040083import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
85/**
86 * The service class that manages LocationProviders and issues location
87 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 */
Brian Muramatsubb95cb92012-08-29 10:43:21 -070089public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070091 public static final boolean D = false;
92
93 private static final String WAKELOCK_KEY = TAG;
94 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
Victoria Lease37425c32012-10-16 16:08:48 -070096 // Location resolution level: no location data whatsoever
97 private static final int RESOLUTION_LEVEL_NONE = 0;
98 // Location resolution level: coarse location data only
99 private static final int RESOLUTION_LEVEL_COARSE = 1;
100 // Location resolution level: fine location data
101 private static final int RESOLUTION_LEVEL_FINE = 2;
102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700104 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700106 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400107 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700108 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
109
110 private static final String NETWORK_LOCATION_SERVICE_ACTION =
111 "com.android.location.service.v2.NetworkLocationProvider";
112 private static final String FUSED_LOCATION_SERVICE_ACTION =
113 "com.android.location.service.FusedLocationProvider";
114
115 private static final int MSG_LOCATION_CHANGED = 1;
116
Nick Pellyf1be6862012-05-15 10:53:42 -0700117 // Location Providers may sometimes deliver location updates
118 // slightly faster that requested - provide grace period so
119 // we don't unnecessarily filter events that are otherwise on
120 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700121 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700122
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700123 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
124
125 private final Context mContext;
126
127 // used internally for synchronization
128 private final Object mLock = new Object();
129
130 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700131 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700132 private GeofenceManager mGeofenceManager;
133 private PowerManager.WakeLock mWakeLock;
134 private PackageManager mPackageManager;
135 private GeocoderProxy mGeocodeProvider;
136 private IGpsStatusProvider mGpsStatusProvider;
137 private INetInitiatedListener mNetInitiatedListener;
138 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700139 private PassiveProvider mPassiveProvider; // track passive provider for special cases
140 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700141
142 // --- fields below are protected by mWakeLock ---
143 private int mPendingBroadcasts;
144
145 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 // Set of providers that are explicitly enabled
147 private final Set<String> mEnabledProviders = new HashSet<String>();
148
149 // Set of providers that are explicitly disabled
150 private final Set<String> mDisabledProviders = new HashSet<String>();
151
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700152 // Mock (test) providers
153 private final HashMap<String, MockProvider> mMockProviders =
154 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700156 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400157 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700159 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500160 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700161 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400162
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700163 // real providers, saved here when mocked out
164 private final HashMap<String, LocationProviderInterface> mRealProviders =
165 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 // mapping from provider name to provider
168 private final HashMap<String, LocationProviderInterface> mProvidersByName =
169 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700171 // mapping from provider name to all its UpdateRecords
172 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
173 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700174
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700175 // mapping from provider name to last known location
176 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700178 // all providers that operate over proxy, for authorizing incoming location
179 private final ArrayList<LocationProviderProxy> mProxyProviders =
180 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181
Victoria Lease38389b62012-09-30 11:44:22 -0700182 // current active user on the device - other users are denied location data
183 private int mCurrentUserId = UserHandle.USER_OWNER;
184
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 public LocationManagerService(Context context) {
186 super();
187 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800188
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700189 if (D) Log.d(TAG, "Constructed");
190
191 // most startup is deferred until systemReady()
192 }
193
194 public void systemReady() {
195 Thread thread = new Thread(null, this, THREAD_NAME);
196 thread.start();
197 }
198
199 @Override
200 public void run() {
201 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
202 Looper.prepare();
203 mLocationHandler = new LocationWorkerHandler();
204 init();
205 Looper.loop();
206 }
207
208 private void init() {
209 if (D) Log.d(TAG, "init()");
210
211 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
212 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
213 mPackageManager = mContext.getPackageManager();
214
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700215 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
216 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700217 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700218
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700219 synchronized (mLock) {
220 loadProvidersLocked();
221 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700222
Nick Pelly4035f5a2012-08-17 14:43:49 -0700223 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700224
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700225 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700226 mContext.getContentResolver().registerContentObserver(
227 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
228 new ContentObserver(mLocationHandler) {
229 @Override
230 public void onChange(boolean selfChange) {
231 synchronized (mLock) {
232 updateProvidersLocked();
233 }
234 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700235 }, UserHandle.USER_ALL);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700236 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700237
Victoria Lease38389b62012-09-30 11:44:22 -0700238 // listen for user change
239 IntentFilter intentFilter = new IntentFilter();
240 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
241
242 mContext.registerReceiverAsUser(new BroadcastReceiver() {
243 @Override
244 public void onReceive(Context context, Intent intent) {
245 String action = intent.getAction();
246 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
247 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
248 }
249 }
250 }, UserHandle.ALL, intentFilter, null, null);
251
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700252 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700253 }
254
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500255 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
256 PackageManager pm = mContext.getPackageManager();
257 String systemPackageName = mContext.getPackageName();
258 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
259
260 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
261 new Intent(FUSED_LOCATION_SERVICE_ACTION),
262 PackageManager.GET_META_DATA, mCurrentUserId);
263 for (ResolveInfo rInfo : rInfos) {
264 String packageName = rInfo.serviceInfo.packageName;
265
266 // Check that the signature is in the list of supported sigs. If it's not in
267 // this list the standard provider binding logic won't bind to it.
268 try {
269 PackageInfo pInfo;
270 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
271 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
272 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
273 ", but has wrong signature, ignoring");
274 continue;
275 }
276 } catch (NameNotFoundException e) {
277 Log.e(TAG, "missing package: " + packageName);
278 continue;
279 }
280
281 // Get the version info
282 if (rInfo.serviceInfo.metaData == null) {
283 Log.w(TAG, "Found fused provider without metadata: " + packageName);
284 continue;
285 }
286
287 int version = rInfo.serviceInfo.metaData.getInt(
288 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
289 if (version == 0) {
290 // This should be the fallback fused location provider.
291
292 // Make sure it's in the system partition.
293 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
294 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
295 continue;
296 }
297
298 // Check that the fallback is signed the same as the OS
299 // as a proxy for coreApp="true"
300 if (pm.checkSignatures(systemPackageName, packageName)
301 != PackageManager.SIGNATURE_MATCH) {
302 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
303 + packageName);
304 continue;
305 }
306
307 // Found a valid fallback.
308 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
309 return;
310 } else {
311 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
312 }
313 }
314
315 throw new IllegalStateException("Unable to find a fused location provider that is in the "
316 + "system partition with version 0 and signed with the platform certificate. "
317 + "Such a package is needed to provide a default fused location provider in the "
318 + "event that no other fused location provider has been installed or is currently "
319 + "available. For example, coreOnly boot mode when decrypting the data "
320 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
321 }
322
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700323 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700324 // create a passive location provider, which is always enabled
325 PassiveProvider passiveProvider = new PassiveProvider(this);
326 addProviderLocked(passiveProvider);
327 mEnabledProviders.add(passiveProvider.getName());
328 mPassiveProvider = passiveProvider;
329
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700330 if (GpsLocationProvider.isSupported()) {
331 // Create a gps location provider
332 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
333 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
334 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
335 addProviderLocked(gpsProvider);
336 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
337 }
338
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700339 /*
340 Load package name(s) containing location provider support.
341 These packages can contain services implementing location providers:
342 Geocoder Provider, Network Location Provider, and
343 Fused Location Provider. They will each be searched for
344 service components implementing these providers.
345 The location framework also has support for installation
346 of new location providers at run-time. The new package does not
347 have to be explicitly listed here, however it must have a signature
348 that matches the signature of at least one package on this list.
349 */
350 Resources resources = mContext.getResources();
351 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500352 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700353 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500354 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
355 Arrays.toString(pkgs));
356 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
357
358 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700359
360 // bind to network provider
361 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
362 mContext,
363 LocationManager.NETWORK_PROVIDER,
364 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700365 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700366 if (networkProvider != null) {
367 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
368 mProxyProviders.add(networkProvider);
369 addProviderLocked(networkProvider);
370 } else {
371 Slog.w(TAG, "no network location provider found");
372 }
373
374 // bind to fused provider
375 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
376 mContext,
377 LocationManager.FUSED_PROVIDER,
378 FUSED_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700379 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700380 if (fusedLocationProvider != null) {
381 addProviderLocked(fusedLocationProvider);
382 mProxyProviders.add(fusedLocationProvider);
383 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700384 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700385 } else {
386 Slog.e(TAG, "no fused location provider found",
387 new IllegalStateException("Location service needs a fused location provider"));
388 }
389
390 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700391 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
392 mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700393 if (mGeocodeProvider == null) {
394 Slog.e(TAG, "no geocoder provider found");
395 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700396 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700399 * Called when the device's active user changes.
400 * @param userId the new active user's UserId
401 */
402 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700403 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700404 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700405 mLastLocation.clear();
406 for (LocationProviderInterface p : mProviders) {
407 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Lease269518e2012-10-29 08:25:39 -0700408 p.switchUser(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700409 }
Victoria Lease38389b62012-09-30 11:44:22 -0700410 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700411 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700412 }
413 }
414
415 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
417 * location updates.
418 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700419 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700420 final int mUid; // uid of receiver
421 final int mPid; // pid of receiver
422 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700423 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 final ILocationListener mListener;
426 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700428
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400429 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700430
Mike Lockwood48f17512009-04-23 09:12:08 -0700431 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700433 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
434 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700437 if (listener != null) {
438 mKey = listener.asBinder();
439 } else {
440 mKey = intent;
441 }
Victoria Lease37425c32012-10-16 16:08:48 -0700442 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700443 mUid = uid;
444 mPid = pid;
445 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 }
447
448 @Override
449 public boolean equals(Object otherObj) {
450 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700451 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 }
453 return false;
454 }
455
456 @Override
457 public int hashCode() {
458 return mKey.hashCode();
459 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 @Override
462 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700463 StringBuilder s = new StringBuilder();
464 s.append("Reciever[");
465 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700467 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700469 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700471 for (String p : mUpdateRecords.keySet()) {
472 s.append(" ").append(mUpdateRecords.get(p).toString());
473 }
474 s.append("]");
475 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 }
477
478 public boolean isListener() {
479 return mListener != null;
480 }
481
482 public boolean isPendingIntent() {
483 return mPendingIntent != null;
484 }
485
486 public ILocationListener getListener() {
487 if (mListener != null) {
488 return mListener;
489 }
490 throw new IllegalStateException("Request for non-existent listener");
491 }
492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
494 if (mListener != null) {
495 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700496 synchronized (this) {
497 // synchronize to ensure incrementPendingBroadcastsLocked()
498 // is called before decrementPendingBroadcasts()
499 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700500 // call this after broadcasting so we do not increment
501 // if we throw an exeption.
502 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 } catch (RemoteException e) {
505 return false;
506 }
507 } else {
508 Intent statusChanged = new Intent();
509 statusChanged.putExtras(extras);
510 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
511 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700512 synchronized (this) {
513 // synchronize to ensure incrementPendingBroadcastsLocked()
514 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700515 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700516 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700517 // call this after broadcasting so we do not increment
518 // if we throw an exeption.
519 incrementPendingBroadcastsLocked();
520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 } catch (PendingIntent.CanceledException e) {
522 return false;
523 }
524 }
525 return true;
526 }
527
528 public boolean callLocationChangedLocked(Location location) {
529 if (mListener != null) {
530 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700531 synchronized (this) {
532 // synchronize to ensure incrementPendingBroadcastsLocked()
533 // is called before decrementPendingBroadcasts()
534 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700535 // call this after broadcasting so we do not increment
536 // if we throw an exeption.
537 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 } catch (RemoteException e) {
540 return false;
541 }
542 } else {
543 Intent locationChanged = new Intent();
544 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
545 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700546 synchronized (this) {
547 // synchronize to ensure incrementPendingBroadcastsLocked()
548 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700549 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700550 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700551 // call this after broadcasting so we do not increment
552 // if we throw an exeption.
553 incrementPendingBroadcastsLocked();
554 }
555 } catch (PendingIntent.CanceledException e) {
556 return false;
557 }
558 }
559 return true;
560 }
561
562 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
563 if (mListener != null) {
564 try {
565 synchronized (this) {
566 // synchronize to ensure incrementPendingBroadcastsLocked()
567 // is called before decrementPendingBroadcasts()
568 if (enabled) {
569 mListener.onProviderEnabled(provider);
570 } else {
571 mListener.onProviderDisabled(provider);
572 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700573 // call this after broadcasting so we do not increment
574 // if we throw an exeption.
575 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700576 }
577 } catch (RemoteException e) {
578 return false;
579 }
580 } else {
581 Intent providerIntent = new Intent();
582 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
583 try {
584 synchronized (this) {
585 // synchronize to ensure incrementPendingBroadcastsLocked()
586 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700587 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700588 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700589 // call this after broadcasting so we do not increment
590 // if we throw an exeption.
591 incrementPendingBroadcastsLocked();
592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 } catch (PendingIntent.CanceledException e) {
594 return false;
595 }
596 }
597 return true;
598 }
599
Nick Pellyf1be6862012-05-15 10:53:42 -0700600 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700602 if (D) Log.d(TAG, "Location listener died");
603
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400604 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 removeUpdatesLocked(this);
606 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700607 synchronized (this) {
608 if (mPendingBroadcasts > 0) {
609 LocationManagerService.this.decrementPendingBroadcasts();
610 mPendingBroadcasts = 0;
611 }
612 }
613 }
614
Nick Pellye0fd6932012-07-11 10:26:13 -0700615 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700616 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
617 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400618 synchronized (this) {
619 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700620 }
621 }
622
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400623 // this must be called while synchronized by caller in a synchronized block
624 // containing the sending of the broadcaset
625 private void incrementPendingBroadcastsLocked() {
626 if (mPendingBroadcasts++ == 0) {
627 LocationManagerService.this.incrementPendingBroadcasts();
628 }
629 }
630
631 private void decrementPendingBroadcastsLocked() {
632 if (--mPendingBroadcasts == 0) {
633 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700634 }
635 }
636 }
637
Nick Pellye0fd6932012-07-11 10:26:13 -0700638 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700639 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400640 //Do not use getReceiver here as that will add the ILocationListener to
641 //the receiver list if it is not found. If it is not found then the
642 //LocationListener was removed when it had a pending broadcast and should
643 //not be added back.
644 IBinder binder = listener.asBinder();
645 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700646 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400647 synchronized (receiver) {
648 // so wakelock calls will succeed
649 long identity = Binder.clearCallingIdentity();
650 receiver.decrementPendingBroadcastsLocked();
651 Binder.restoreCallingIdentity(identity);
652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654 }
655
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700656 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400657 mProviders.add(provider);
658 mProvidersByName.put(provider.getName(), provider);
659 }
660
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 private void removeProviderLocked(LocationProviderInterface provider) {
662 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400663 mProviders.remove(provider);
664 mProvidersByName.remove(provider.getName());
665 }
666
Mike Lockwood3d12b512009-04-21 23:25:35 -0700667
Victoria Lease269518e2012-10-29 08:25:39 -0700668 private boolean isAllowedBySettingsLocked(String provider, int userId) {
669 if (userId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700670 return false;
671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 if (mEnabledProviders.contains(provider)) {
673 return true;
674 }
675 if (mDisabledProviders.contains(provider)) {
676 return false;
677 }
678 // Use system settings
679 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680
Victoria Leaseb711d572012-10-02 13:14:11 -0700681 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 }
683
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700684 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700685 * Returns the permission string associated with the specified resolution level.
686 *
687 * @param resolutionLevel the resolution level
688 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700689 */
Victoria Lease37425c32012-10-16 16:08:48 -0700690 private String getResolutionPermission(int resolutionLevel) {
691 switch (resolutionLevel) {
692 case RESOLUTION_LEVEL_FINE:
693 return android.Manifest.permission.ACCESS_FINE_LOCATION;
694 case RESOLUTION_LEVEL_COARSE:
695 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
696 default:
697 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700699 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700700
Victoria Leaseda479c52012-10-15 15:24:16 -0700701 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700702 * Returns the resolution level allowed to the given PID/UID pair.
703 *
704 * @param pid the PID
705 * @param uid the UID
706 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700707 */
Victoria Lease37425c32012-10-16 16:08:48 -0700708 private int getAllowedResolutionLevel(int pid, int uid) {
709 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
710 pid, uid) == PackageManager.PERMISSION_GRANTED) {
711 return RESOLUTION_LEVEL_FINE;
712 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
713 pid, uid) == PackageManager.PERMISSION_GRANTED) {
714 return RESOLUTION_LEVEL_COARSE;
715 } else {
716 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700717 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700718 }
719
720 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700721 * Returns the resolution level allowed to the caller
722 *
723 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700724 */
Victoria Lease37425c32012-10-16 16:08:48 -0700725 private int getCallerAllowedResolutionLevel() {
726 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
727 }
728
729 /**
730 * Throw SecurityException if specified resolution level is insufficient to use geofences.
731 *
732 * @param allowedResolutionLevel resolution level allowed to caller
733 */
734 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
735 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700736 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 }
739
Victoria Lease37425c32012-10-16 16:08:48 -0700740 /**
741 * Return the minimum resolution level required to use the specified location provider.
742 *
743 * @param provider the name of the location provider
744 * @return minimum resolution level required for provider
745 */
746 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700747 if (LocationManager.GPS_PROVIDER.equals(provider) ||
748 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
749 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700750 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700751 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
752 LocationManager.FUSED_PROVIDER.equals(provider)) {
753 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700754 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700755 } else {
756 // mock providers
757 LocationProviderInterface lp = mMockProviders.get(provider);
758 if (lp != null) {
759 ProviderProperties properties = lp.getProperties();
760 if (properties != null) {
761 if (properties.mRequiresSatellite) {
762 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700763 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700764 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
765 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700766 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700767 }
768 }
769 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700770 }
Victoria Lease37425c32012-10-16 16:08:48 -0700771 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700772 }
773
Victoria Lease37425c32012-10-16 16:08:48 -0700774 /**
775 * Throw SecurityException if specified resolution level is insufficient to use the named
776 * location provider.
777 *
778 * @param allowedResolutionLevel resolution level allowed to caller
779 * @param providerName the name of the location provider
780 */
781 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
782 String providerName) {
783 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
784 if (allowedResolutionLevel < requiredResolutionLevel) {
785 switch (requiredResolutionLevel) {
786 case RESOLUTION_LEVEL_FINE:
787 throw new SecurityException("\"" + providerName + "\" location provider " +
788 "requires ACCESS_FINE_LOCATION permission.");
789 case RESOLUTION_LEVEL_COARSE:
790 throw new SecurityException("\"" + providerName + "\" location provider " +
791 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
792 default:
793 throw new SecurityException("Insufficient permission for \"" + providerName +
794 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700795 }
796 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700797 }
798
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700799 /**
800 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700801 * fused, also including ones that are not permitted to
802 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700803 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700804 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700806 ArrayList<String> out;
807 synchronized (mLock) {
808 out = new ArrayList<String>(mProviders.size());
809 for (LocationProviderInterface provider : mProviders) {
810 String name = provider.getName();
811 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700812 continue;
813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 out.add(name);
815 }
816 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700817
818 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 return out;
820 }
821
Mike Lockwood03ca2162010-04-01 08:10:09 -0700822 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700823 * Return all providers by name, that match criteria and are optionally
824 * enabled.
825 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700826 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700827 @Override
828 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700829 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700830 ArrayList<String> out;
Victoria Lease269518e2012-10-29 08:25:39 -0700831 int callingUserId = UserHandle.getCallingUserId();
832 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700833 try {
834 synchronized (mLock) {
835 out = new ArrayList<String>(mProviders.size());
836 for (LocationProviderInterface provider : mProviders) {
837 String name = provider.getName();
838 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700839 continue;
840 }
Victoria Lease37425c32012-10-16 16:08:48 -0700841 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease269518e2012-10-29 08:25:39 -0700842 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700843 continue;
844 }
845 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
846 name, provider.getProperties(), criteria)) {
847 continue;
848 }
849 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700850 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700851 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700852 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700853 } finally {
854 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700855 }
856
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700857 if (D) Log.d(TAG, "getProviders()=" + out);
858 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700859 }
860
861 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700862 * Return the name of the best provider given a Criteria object.
863 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700864 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700865 * has been deprecated as well. So this method now uses
866 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700867 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700868 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700869 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700870 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700871
872 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700873 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700874 result = pickBest(providers);
875 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
876 return result;
877 }
878 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700879 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700880 result = pickBest(providers);
881 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
882 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700883 }
884
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700885 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700886 return null;
887 }
888
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700889 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700890 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700891 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700892 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
893 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700894 } else {
895 return providers.get(0);
896 }
897 }
898
Nick Pellye0fd6932012-07-11 10:26:13 -0700899 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700900 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
901 LocationProviderInterface p = mProvidersByName.get(provider);
902 if (p == null) {
903 throw new IllegalArgumentException("provider=" + provider);
904 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700905
906 boolean result = LocationProvider.propertiesMeetCriteria(
907 p.getName(), p.getProperties(), criteria);
908 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
909 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700910 }
911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700913 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400914 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500915 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 boolean isEnabled = p.isEnabled();
917 String name = p.getName();
Victoria Lease269518e2012-10-29 08:25:39 -0700918 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700920 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700921 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700923 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700924 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700926 }
927 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700928 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
929 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 }
931 }
932
Victoria Leaseb711d572012-10-02 13:14:11 -0700933 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 int listeners = 0;
935
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500936 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700937 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938
939 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
942 if (records != null) {
943 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700944 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -0700946 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700947 // Sends a notification message to the receiver
948 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
949 if (deadReceivers == null) {
950 deadReceivers = new ArrayList<Receiver>();
951 }
952 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700954 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 }
957 }
958
959 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700960 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 removeUpdatesLocked(deadReceivers.get(i));
962 }
963 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 if (enabled) {
966 p.enable();
967 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700968 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 }
970 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 }
974
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700975 private void applyRequirementsLocked(String provider) {
976 LocationProviderInterface p = mProvidersByName.get(provider);
977 if (p == null) return;
978
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700980 WorkSource worksource = new WorkSource();
981 ProviderRequest providerRequest = new ProviderRequest();
982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700984 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -0700985 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700986 LocationRequest locationRequest = record.mRequest;
987 providerRequest.locationRequests.add(locationRequest);
988 if (locationRequest.getInterval() < providerRequest.interval) {
989 providerRequest.reportLocation = true;
990 providerRequest.interval = locationRequest.getInterval();
991 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700992 }
993 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700994
995 if (providerRequest.reportLocation) {
996 // calculate who to blame for power
997 // This is somewhat arbitrary. We pick a threshold interval
998 // that is slightly higher that the minimum interval, and
999 // spread the blame across all applications with a request
1000 // under that threshold.
1001 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1002 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001003 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001004 LocationRequest locationRequest = record.mRequest;
1005 if (locationRequest.getInterval() <= thresholdInterval) {
1006 worksource.add(record.mReceiver.mUid);
1007 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001008 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001009 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
1011 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001012
1013 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1014 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 }
1016
1017 private class UpdateRecord {
1018 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001019 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001021 Location mLastFixBroadcast;
1022 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023
1024 /**
1025 * Note: must be constructed with lock held.
1026 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001027 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001029 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031
1032 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1033 if (records == null) {
1034 records = new ArrayList<UpdateRecord>();
1035 mRecordsByProvider.put(provider, records);
1036 }
1037 if (!records.contains(this)) {
1038 records.add(this);
1039 }
1040 }
1041
1042 /**
1043 * Method to be called when a record will no longer be used. Calling this multiple times
1044 * must have the same effect as calling it once.
1045 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001046 void disposeLocked(boolean removeReceiver) {
1047 // remove from mRecordsByProvider
1048 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1049 if (globalRecords != null) {
1050 globalRecords.remove(this);
1051 }
1052
1053 if (!removeReceiver) return; // the caller will handle the rest
1054
1055 // remove from Receiver#mUpdateRecords
1056 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1057 if (receiverRecords != null) {
1058 receiverRecords.remove(this.mProvider);
1059
1060 // and also remove the Receiver if it has no more update records
1061 if (removeReceiver && receiverRecords.size() == 0) {
1062 removeUpdatesLocked(mReceiver);
1063 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001064 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 }
1066
1067 @Override
1068 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001069 StringBuilder s = new StringBuilder();
1070 s.append("UpdateRecord[");
1071 s.append(mProvider);
1072 s.append(' ').append(mReceiver.mPackageName).append('(');
1073 s.append(mReceiver.mUid).append(')');
1074 s.append(' ').append(mRequest);
1075 s.append(']');
1076 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 }
1079
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001080 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001081 IBinder binder = listener.asBinder();
1082 Receiver receiver = mReceivers.get(binder);
1083 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001084 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001085 mReceivers.put(binder, receiver);
1086
1087 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001088 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001089 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001090 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001091 return null;
1092 }
1093 }
1094 return receiver;
1095 }
1096
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001097 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001098 Receiver receiver = mReceivers.get(intent);
1099 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001100 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001101 mReceivers.put(intent, receiver);
1102 }
1103 return receiver;
1104 }
1105
Victoria Lease37425c32012-10-16 16:08:48 -07001106 /**
1107 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1108 * and consistency requirements.
1109 *
1110 * @param request the LocationRequest from which to create a sanitized version
1111 * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
1112 * constraints
1113 * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
1114 * @return a version of request that meets the given resolution and consistency requirements
1115 * @hide
1116 */
1117 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1118 LocationRequest sanitizedRequest = new LocationRequest(request);
1119 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1120 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001121 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001122 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001123 break;
1124 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001125 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001126 break;
1127 }
1128 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001129 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1130 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001131 }
Victoria Lease37425c32012-10-16 16:08:48 -07001132 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1133 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001134 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001135 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001136 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001137 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001138 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001139 }
Victoria Lease37425c32012-10-16 16:08:48 -07001140 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001141 }
1142
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001143 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001144 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001145 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001146 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001147 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001148 String[] packages = mPackageManager.getPackagesForUid(uid);
1149 if (packages == null) {
1150 throw new SecurityException("invalid UID " + uid);
1151 }
1152 for (String pkg : packages) {
1153 if (packageName.equals(pkg)) return;
1154 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001155 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001156 }
1157
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001158 private void checkPendingIntent(PendingIntent intent) {
1159 if (intent == null) {
1160 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001161 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001162 }
1163
1164 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1165 int pid, int uid, String packageName) {
1166 if (intent == null && listener == null) {
1167 throw new IllegalArgumentException("need eiter listener or intent");
1168 } else if (intent != null && listener != null) {
1169 throw new IllegalArgumentException("cannot register both listener and intent");
1170 } else if (intent != null) {
1171 checkPendingIntent(intent);
1172 return getReceiver(intent, pid, uid, packageName);
1173 } else {
1174 return getReceiver(listener, pid, uid, packageName);
1175 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001176 }
1177
Nick Pellye0fd6932012-07-11 10:26:13 -07001178 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001179 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1180 PendingIntent intent, String packageName) {
1181 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1182 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001183 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1184 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1185 request.getProvider());
1186 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001188 final int pid = Binder.getCallingPid();
1189 final int uid = Binder.getCallingUid();
1190 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001192 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 long identity = Binder.clearCallingIdentity();
1194 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001195 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001196 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 } finally {
1199 Binder.restoreCallingIdentity(identity);
1200 }
1201 }
1202
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001203 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1204 int pid, int uid, String packageName) {
1205 // Figure out the provider. Either its explicitly request (legacy use cases), or
1206 // use the fused provider
1207 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1208 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001209 if (name == null) {
1210 throw new IllegalArgumentException("provider name must not be null");
1211 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001212 LocationProviderInterface provider = mProvidersByName.get(name);
1213 if (provider == null) {
1214 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1215 }
1216
1217 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1218 name + " " + request + " from " + packageName + "(" + uid + ")");
1219
1220 UpdateRecord record = new UpdateRecord(name, request, receiver);
1221 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1222 if (oldRecord != null) {
1223 oldRecord.disposeLocked(false);
1224 }
1225
Victoria Lease269518e2012-10-29 08:25:39 -07001226 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001227 if (isProviderEnabled) {
1228 applyRequirementsLocked(name);
1229 } else {
1230 // Notify the listener that updates are currently disabled
1231 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 }
1233 }
1234
Nick Pellye0fd6932012-07-11 10:26:13 -07001235 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1237 String packageName) {
1238 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001239
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001240 final int pid = Binder.getCallingPid();
1241 final int uid = Binder.getCallingUid();
1242 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1243
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001244 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001245 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001247 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001248 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001250 } finally {
1251 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 }
1253 }
1254
1255 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001256 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1257
1258 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1259 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1260 synchronized (receiver) {
1261 if (receiver.mPendingBroadcasts > 0) {
1262 decrementPendingBroadcasts();
1263 receiver.mPendingBroadcasts = 0;
1264 }
1265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 }
1267
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001268 // Record which providers were associated with this listener
1269 HashSet<String> providers = new HashSet<String>();
1270 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1271 if (oldRecords != null) {
1272 // Call dispose() on the obsolete update records.
1273 for (UpdateRecord record : oldRecords.values()) {
1274 record.disposeLocked(false);
1275 }
1276 // Accumulate providers
1277 providers.addAll(oldRecords.keySet());
1278 }
1279
1280 // update provider
1281 for (String provider : providers) {
1282 // If provider is already disabled, don't need to do anything
Victoria Lease269518e2012-10-29 08:25:39 -07001283 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 }
1286
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001287 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 }
1289 }
1290
Nick Pellye0fd6932012-07-11 10:26:13 -07001291 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001292 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001293 if (D) Log.d(TAG, "getLastLocation: " + request);
1294 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001295 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001296 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001297 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1298 request.getProvider());
1299 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001300
Victoria Lease269518e2012-10-29 08:25:39 -07001301 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001302 try {
1303 if (mBlacklist.isBlacklisted(packageName)) {
1304 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1305 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001306 return null;
1307 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001308
1309 synchronized (mLock) {
1310 // Figure out the provider. Either its explicitly request (deprecated API's),
1311 // or use the fused provider
1312 String name = request.getProvider();
1313 if (name == null) name = LocationManager.FUSED_PROVIDER;
1314 LocationProviderInterface provider = mProvidersByName.get(name);
1315 if (provider == null) return null;
1316
Victoria Lease269518e2012-10-29 08:25:39 -07001317 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001318
1319 Location location = mLastLocation.get(name);
1320 if (location == null) {
1321 return null;
1322 }
Victoria Lease37425c32012-10-16 16:08:48 -07001323 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001324 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1325 if (noGPSLocation != null) {
1326 return mLocationFudger.getOrCreate(noGPSLocation);
1327 }
Victoria Lease37425c32012-10-16 16:08:48 -07001328 } else {
1329 return location;
Victoria Lease09016ab2012-09-16 12:33:15 -07001330 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001331 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001332 return null;
1333 } finally {
1334 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001335 }
1336 }
1337
1338 @Override
1339 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1340 String packageName) {
1341 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001342 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1343 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001344 checkPendingIntent(intent);
1345 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001346 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1347 request.getProvider());
1348 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001349
Victoria Lease37425c32012-10-16 16:08:48 -07001350 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001351
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001352 // geo-fence manager uses the public location API, need to clear identity
1353 int uid = Binder.getCallingUid();
1354 long identity = Binder.clearCallingIdentity();
1355 try {
Victoria Lease37425c32012-10-16 16:08:48 -07001356 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001357 } finally {
1358 Binder.restoreCallingIdentity(identity);
1359 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001360 }
1361
1362 @Override
1363 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001364 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001365 checkPendingIntent(intent);
1366 checkPackageName(packageName);
1367
1368 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1369
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001370 // geo-fence manager uses the public location API, need to clear identity
1371 long identity = Binder.clearCallingIdentity();
1372 try {
1373 mGeofenceManager.removeFence(geofence, intent);
1374 } finally {
1375 Binder.restoreCallingIdentity(identity);
1376 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001377 }
1378
1379
1380 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001382 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 return false;
1384 }
Victoria Lease37425c32012-10-16 16:08:48 -07001385 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1386 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387
1388 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001389 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001391 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 return false;
1393 }
1394 return true;
1395 }
1396
Nick Pellye0fd6932012-07-11 10:26:13 -07001397 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001399 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001400 try {
1401 mGpsStatusProvider.removeGpsStatusListener(listener);
1402 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001403 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001404 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 }
1406 }
1407
Nick Pellye0fd6932012-07-11 10:26:13 -07001408 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001410 if (provider == null) {
1411 // throw NullPointerException to remain compatible with previous implementation
1412 throw new NullPointerException();
1413 }
Victoria Lease37425c32012-10-16 16:08:48 -07001414 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1415 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001418 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 != PackageManager.PERMISSION_GRANTED)) {
1420 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1421 }
1422
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001423 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001424 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001425 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001426
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001427 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 }
1429 }
1430
Nick Pellye0fd6932012-07-11 10:26:13 -07001431 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001432 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001433 if (Binder.getCallingUid() != Process.myUid()) {
1434 throw new SecurityException(
1435 "calling sendNiResponse from outside of the system is not allowed");
1436 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001437 try {
1438 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001439 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001440 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001441 return false;
1442 }
1443 }
1444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001446 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001447 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 * accessed by the caller
1449 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001450 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001451 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001452 if (mProvidersByName.get(provider) == null) {
1453 return null;
1454 }
1455
Victoria Lease37425c32012-10-16 16:08:48 -07001456 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1457 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001459 LocationProviderInterface p;
1460 synchronized (mLock) {
1461 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 }
1463
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001464 if (p == null) return null;
1465 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 }
1467
Nick Pellye0fd6932012-07-11 10:26:13 -07001468 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001470 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1471 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001472 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1473
Victoria Lease269518e2012-10-29 08:25:39 -07001474 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001475 try {
1476 synchronized (mLock) {
1477 LocationProviderInterface p = mProvidersByName.get(provider);
1478 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001479
Victoria Lease269518e2012-10-29 08:25:39 -07001480 return isAllowedBySettingsLocked(provider, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -07001481 }
1482 } finally {
1483 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001484 }
1485 }
1486
1487 private void checkCallerIsProvider() {
1488 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1489 == PackageManager.PERMISSION_GRANTED) {
1490 return;
1491 }
1492
1493 // Previously we only used the INSTALL_LOCATION_PROVIDER
1494 // check. But that is system or signature
1495 // protection level which is not flexible enough for
1496 // providers installed oustide the system image. So
1497 // also allow providers with a UID matching the
1498 // currently bound package name
1499
1500 int uid = Binder.getCallingUid();
1501
1502 if (mGeocodeProvider != null) {
1503 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1504 }
1505 for (LocationProviderProxy proxy : mProxyProviders) {
1506 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1507 }
1508 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1509 "or UID of a currently bound location provider");
1510 }
1511
1512 private boolean doesPackageHaveUid(int uid, String packageName) {
1513 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 return false;
1515 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001516 try {
1517 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1518 if (appInfo.uid != uid) {
1519 return false;
1520 }
1521 } catch (NameNotFoundException e) {
1522 return false;
1523 }
1524 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 }
1526
Nick Pellye0fd6932012-07-11 10:26:13 -07001527 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001528 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001529 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001530
Nick Pelly2eeeec22012-07-18 13:13:37 -07001531 if (!location.isComplete()) {
1532 Log.w(TAG, "Dropping incomplete location: " + location);
1533 return;
1534 }
1535
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001536 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1537 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001538 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001539 mLocationHandler.sendMessageAtFrontOfQueue(m);
1540 }
1541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542
1543 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1544 // Always broadcast the first update
1545 if (lastLoc == null) {
1546 return true;
1547 }
1548
Nick Pellyf1be6862012-05-15 10:53:42 -07001549 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001550 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001551 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001552 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 return false;
1554 }
1555
1556 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001557 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 if (minDistance > 0.0) {
1559 if (loc.distanceTo(lastLoc) <= minDistance) {
1560 return false;
1561 }
1562 }
1563
1564 return true;
1565 }
1566
Mike Lockwooda4903f22010-02-17 06:42:23 -05001567 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001568 if (D) Log.d(TAG, "incoming location: " + location);
1569
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001570 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001571 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572
Laurent Tu60ec50a2012-10-04 17:00:10 -07001573 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001574 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001575 if (p == null) return;
1576
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001577 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001578 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1579 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001580 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001581 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001582 lastLocation = new Location(provider);
1583 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001584 } else {
1585 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1586 if (noGPSLocation == null && lastNoGPSLocation != null) {
1587 // New location has no no-GPS location: adopt last no-GPS location. This is set
1588 // directly into location because we do not want to notify COARSE clients.
1589 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1590 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001591 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001592 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593
Laurent Tu60ec50a2012-10-04 17:00:10 -07001594 // Skip if there are no UpdateRecords for this provider.
1595 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1596 if (records == null || records.size() == 0) return;
1597
Victoria Lease09016ab2012-09-16 12:33:15 -07001598 // Fetch coarse location
1599 Location coarseLocation = null;
1600 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1601 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1602 }
1603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 // Fetch latest status update time
1605 long newStatusUpdateTime = p.getStatusUpdateTime();
1606
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001607 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 Bundle extras = new Bundle();
1609 int status = p.getStatus(extras);
1610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001612 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001615 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001617 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001618
Victoria Lease269518e2012-10-29 08:25:39 -07001619 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1620 if (receiverUserId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001621 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001622 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001623 " (current user: " + mCurrentUserId + ", app: " +
1624 receiver.mPackageName + ")");
1625 }
1626 continue;
1627 }
1628
Nick Pelly4035f5a2012-08-17 14:43:49 -07001629 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1630 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1631 receiver.mPackageName);
1632 continue;
1633 }
1634
Victoria Lease09016ab2012-09-16 12:33:15 -07001635 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001636 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1637 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001638 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001639 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001640 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001641 if (notifyLocation != null) {
1642 Location lastLoc = r.mLastFixBroadcast;
1643 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1644 if (lastLoc == null) {
1645 lastLoc = new Location(notifyLocation);
1646 r.mLastFixBroadcast = lastLoc;
1647 } else {
1648 lastLoc.set(notifyLocation);
1649 }
1650 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1651 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1652 receiverDead = true;
1653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 }
1655 }
1656
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001657 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001659 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001661 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001663 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001664 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001665 }
1666 }
1667
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001668 // track expired records
1669 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1670 if (deadUpdateRecords == null) {
1671 deadUpdateRecords = new ArrayList<UpdateRecord>();
1672 }
1673 deadUpdateRecords.add(r);
1674 }
1675 // track dead receivers
1676 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001677 if (deadReceivers == null) {
1678 deadReceivers = new ArrayList<Receiver>();
1679 }
1680 if (!deadReceivers.contains(receiver)) {
1681 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 }
1683 }
1684 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001685
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001686 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001688 for (Receiver receiver : deadReceivers) {
1689 removeUpdatesLocked(receiver);
1690 }
1691 }
1692 if (deadUpdateRecords != null) {
1693 for (UpdateRecord r : deadUpdateRecords) {
1694 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 }
1696 }
1697 }
1698
1699 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 @Override
1701 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001702 switch (msg.what) {
1703 case MSG_LOCATION_CHANGED:
1704 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1705 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 }
1707 }
1708 }
1709
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001710 private void handleLocationChanged(Location location, boolean passive) {
1711 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001712
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001713 if (!passive) {
1714 // notify passive provider of the new location
1715 mPassiveProvider.updateLocation(location);
1716 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001718 synchronized (mLock) {
Victoria Lease269518e2012-10-29 08:25:39 -07001719 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001720 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724
Mike Lockwoode97ae402010-09-29 15:23:46 -04001725 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1726 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001727 public void onPackageDisappeared(String packageName, int reason) {
1728 // remove all receivers associated with this package name
1729 synchronized (mLock) {
1730 ArrayList<Receiver> deadReceivers = null;
1731
1732 for (Receiver receiver : mReceivers.values()) {
1733 if (receiver.mPackageName.equals(packageName)) {
1734 if (deadReceivers == null) {
1735 deadReceivers = new ArrayList<Receiver>();
1736 }
1737 deadReceivers.add(receiver);
1738 }
1739 }
1740
1741 // perform removal outside of mReceivers loop
1742 if (deadReceivers != null) {
1743 for (Receiver receiver : deadReceivers) {
1744 removeUpdatesLocked(receiver);
1745 }
1746 }
1747 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001748 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001749 };
1750
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 // Wake locks
1752
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001753 private void incrementPendingBroadcasts() {
1754 synchronized (mWakeLock) {
1755 if (mPendingBroadcasts++ == 0) {
1756 try {
1757 mWakeLock.acquire();
1758 log("Acquired wakelock");
1759 } catch (Exception e) {
1760 // This is to catch a runtime exception thrown when we try to release an
1761 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001762 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001763 }
1764 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001765 }
1766 }
1767
1768 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001769 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001770 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001771 try {
1772 // Release wake lock
1773 if (mWakeLock.isHeld()) {
1774 mWakeLock.release();
1775 log("Released wakelock");
1776 } else {
1777 log("Can't release wakelock again!");
1778 }
1779 } catch (Exception e) {
1780 // This is to catch a runtime exception thrown when we try to release an
1781 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001782 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001783 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001784 }
1785 }
1786 }
1787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001788 // Geocoder
1789
Nick Pellye0fd6932012-07-11 10:26:13 -07001790 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001791 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001792 return mGeocodeProvider != null;
1793 }
1794
Nick Pellye0fd6932012-07-11 10:26:13 -07001795 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001797 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001798 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001799 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1800 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001802 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 }
1804
Mike Lockwooda55c3212009-04-15 11:10:11 -04001805
Nick Pellye0fd6932012-07-11 10:26:13 -07001806 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001808 double lowerLeftLatitude, double lowerLeftLongitude,
1809 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001810 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001811
1812 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001813 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1814 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1815 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001816 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001817 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 }
1819
1820 // Mock Providers
1821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 private void checkMockPermissionsSafe() {
1823 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1824 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1825 if (!allowMocks) {
1826 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1827 }
1828
1829 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1830 PackageManager.PERMISSION_GRANTED) {
1831 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001832 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 }
1834
Nick Pellye0fd6932012-07-11 10:26:13 -07001835 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001836 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 checkMockPermissionsSafe();
1838
Mike Lockwooda4903f22010-02-17 06:42:23 -05001839 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1840 throw new IllegalArgumentException("Cannot mock the passive location provider");
1841 }
1842
Mike Lockwood86328a92009-10-23 08:38:25 -04001843 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001844 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001845 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001846 // remove the real provider if we are replacing GPS or network provider
1847 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001848 || LocationManager.NETWORK_PROVIDER.equals(name)
1849 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001850 LocationProviderInterface p = mProvidersByName.get(name);
1851 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001852 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001853 }
1854 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001855 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1857 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001858 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001859 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001860 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 updateProvidersLocked();
1862 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001863 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 }
1865
Nick Pellye0fd6932012-07-11 10:26:13 -07001866 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001867 public void removeTestProvider(String provider) {
1868 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001869 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001870 MockProvider mockProvider = mMockProviders.get(provider);
1871 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1873 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001874 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001875 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001876 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001877
1878 // reinstate real provider if available
1879 LocationProviderInterface realProvider = mRealProviders.get(provider);
1880 if (realProvider != null) {
1881 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001882 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001883 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001885 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 }
1887 }
1888
Nick Pellye0fd6932012-07-11 10:26:13 -07001889 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 public void setTestProviderLocation(String provider, Location loc) {
1891 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001892 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001893 MockProvider mockProvider = mMockProviders.get(provider);
1894 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1896 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001897 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1898 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001899 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001900 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001901 }
1902 }
1903
Nick Pellye0fd6932012-07-11 10:26:13 -07001904 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 public void clearTestProviderLocation(String provider) {
1906 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001907 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001908 MockProvider mockProvider = mMockProviders.get(provider);
1909 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1911 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001912 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 }
1914 }
1915
Nick Pellye0fd6932012-07-11 10:26:13 -07001916 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 public void setTestProviderEnabled(String provider, boolean enabled) {
1918 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001919 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001920 MockProvider mockProvider = mMockProviders.get(provider);
1921 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1923 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001924 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001926 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 mEnabledProviders.add(provider);
1928 mDisabledProviders.remove(provider);
1929 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001930 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001931 mEnabledProviders.remove(provider);
1932 mDisabledProviders.add(provider);
1933 }
1934 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001935 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001936 }
1937 }
1938
Nick Pellye0fd6932012-07-11 10:26:13 -07001939 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 public void clearTestProviderEnabled(String provider) {
1941 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001942 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001943 MockProvider mockProvider = mMockProviders.get(provider);
1944 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1946 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001947 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001948 mEnabledProviders.remove(provider);
1949 mDisabledProviders.remove(provider);
1950 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001951 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 }
1953 }
1954
Nick Pellye0fd6932012-07-11 10:26:13 -07001955 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1957 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001958 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001959 MockProvider mockProvider = mMockProviders.get(provider);
1960 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001961 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1962 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001963 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001964 }
1965 }
1966
Nick Pellye0fd6932012-07-11 10:26:13 -07001967 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 public void clearTestProviderStatus(String provider) {
1969 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001970 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001971 MockProvider mockProvider = mMockProviders.get(provider);
1972 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1974 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001975 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 }
1977 }
1978
1979 private void log(String log) {
1980 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001981 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 }
1983 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001984
1985 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1987 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1988 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001989 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 + Binder.getCallingPid()
1991 + ", uid=" + Binder.getCallingUid());
1992 return;
1993 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001994
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001995 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001998 for (Receiver receiver : mReceivers.values()) {
1999 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002001 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002002 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2003 pw.println(" " + entry.getKey() + ":");
2004 for (UpdateRecord record : entry.getValue()) {
2005 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002006 }
2007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002009 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2010 String provider = entry.getKey();
2011 Location location = entry.getValue();
2012 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002014
Nick Pellye0fd6932012-07-11 10:26:13 -07002015 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002017 if (mEnabledProviders.size() > 0) {
2018 pw.println(" Enabled Providers:");
2019 for (String i : mEnabledProviders) {
2020 pw.println(" " + i);
2021 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002023 }
2024 if (mDisabledProviders.size() > 0) {
2025 pw.println(" Disabled Providers:");
2026 for (String i : mDisabledProviders) {
2027 pw.println(" " + i);
2028 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002030 pw.append(" ");
2031 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 if (mMockProviders.size() > 0) {
2033 pw.println(" Mock Providers:");
2034 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002035 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 }
2037 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002038
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002039 pw.append(" fudger: ");
2040 mLocationFudger.dump(fd, pw, args);
2041
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002042 if (args.length > 0 && "short".equals(args[0])) {
2043 return;
2044 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002045 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002046 pw.print(provider.getName() + " Internal State");
2047 if (provider instanceof LocationProviderProxy) {
2048 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2049 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002050 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002051 pw.println(":");
2052 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002053 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 }
2055 }
2056}