blob: 83b94e2c25d8a0aad8f6d46b5cd4864a7a36b776 [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;
Victoria Lease5cd731a2012-12-19 15:04:21 -080049import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070051import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.Message;
53import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070054import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070056import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070057import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070058import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080061import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
Mike Lockwoode97ae402010-09-29 15:23:46 -040063import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070064import com.android.internal.location.ProviderProperties;
65import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040066import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070067import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040068import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070069import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070070import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040071import com.android.server.location.LocationProviderInterface;
72import com.android.server.location.LocationProviderProxy;
73import com.android.server.location.MockProvider;
74import com.android.server.location.PassiveProvider;
75
76import java.io.FileDescriptor;
77import java.io.PrintWriter;
78import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070079import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040080import java.util.HashMap;
81import java.util.HashSet;
82import java.util.List;
83import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040084import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
86/**
87 * The service class that manages LocationProviders and issues location
88 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 */
Victoria Lease5cd731a2012-12-19 15:04:21 -080090public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070092 public static final boolean D = false;
93
94 private static final String WAKELOCK_KEY = TAG;
95 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
Victoria Lease37425c32012-10-16 16:08:48 -070097 // Location resolution level: no location data whatsoever
98 private static final int RESOLUTION_LEVEL_NONE = 0;
99 // Location resolution level: coarse location data only
100 private static final int RESOLUTION_LEVEL_COARSE = 1;
101 // Location resolution level: fine location data
102 private static final int RESOLUTION_LEVEL_FINE = 2;
103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700105 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700107 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400108 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700109 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
110
111 private static final String NETWORK_LOCATION_SERVICE_ACTION =
112 "com.android.location.service.v2.NetworkLocationProvider";
113 private static final String FUSED_LOCATION_SERVICE_ACTION =
114 "com.android.location.service.FusedLocationProvider";
115
116 private static final int MSG_LOCATION_CHANGED = 1;
117
Nick Pellyf1be6862012-05-15 10:53:42 -0700118 // Location Providers may sometimes deliver location updates
119 // slightly faster that requested - provide grace period so
120 // we don't unnecessarily filter events that are otherwise on
121 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700122 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700123
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700124 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
125
126 private final Context mContext;
127
128 // used internally for synchronization
129 private final Object mLock = new Object();
130
Victoria Lease5cd731a2012-12-19 15:04:21 -0800131 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700132 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700133 private GeofenceManager mGeofenceManager;
134 private PowerManager.WakeLock mWakeLock;
135 private PackageManager mPackageManager;
136 private GeocoderProxy mGeocodeProvider;
137 private IGpsStatusProvider mGpsStatusProvider;
138 private INetInitiatedListener mNetInitiatedListener;
139 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700140 private PassiveProvider mPassiveProvider; // track passive provider for special cases
141 private LocationBlacklist mBlacklist;
Victoria Lease5cd731a2012-12-19 15:04:21 -0800142 private HandlerThread mHandlerThread;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700143
144 // --- fields below are protected by mWakeLock ---
145 private int mPendingBroadcasts;
146
147 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 // Set of providers that are explicitly enabled
149 private final Set<String> mEnabledProviders = new HashSet<String>();
150
151 // Set of providers that are explicitly disabled
152 private final Set<String> mDisabledProviders = new HashSet<String>();
153
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700154 // Mock (test) providers
155 private final HashMap<String, MockProvider> mMockProviders =
156 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700158 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400159 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700161 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500162 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700163 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400164
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700165 // real providers, saved here when mocked out
166 private final HashMap<String, LocationProviderInterface> mRealProviders =
167 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // mapping from provider name to provider
170 private final HashMap<String, LocationProviderInterface> mProvidersByName =
171 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700173 // mapping from provider name to all its UpdateRecords
174 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
175 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700176
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 // mapping from provider name to last known location
178 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700180 // all providers that operate over proxy, for authorizing incoming location
181 private final ArrayList<LocationProviderProxy> mProxyProviders =
182 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
Victoria Lease38389b62012-09-30 11:44:22 -0700184 // current active user on the device - other users are denied location data
185 private int mCurrentUserId = UserHandle.USER_OWNER;
186
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700187 public LocationManagerService(Context context) {
188 super();
189 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800190
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700191 if (D) Log.d(TAG, "Constructed");
192
193 // most startup is deferred until systemReady()
194 }
195
196 public void systemReady() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700197 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800198 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700199
Victoria Lease5cd731a2012-12-19 15:04:21 -0800200 // fetch package manager
201 mPackageManager = mContext.getPackageManager();
202
203 // prepare wake lock
204 PowerManager powerManager =
205 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
206 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
207
208 // prepare worker thread
209 mHandlerThread = new HandlerThread(THREAD_NAME, Process.THREAD_PRIORITY_BACKGROUND);
210 mHandlerThread.start();
211 mLocationHandler = new LocationWorkerHandler(mHandlerThread.getLooper());
212
213 // prepare mLocationHandler's dependents
214 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
215 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
216 mBlacklist.init();
217 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
218
219 // prepare providers
220 loadProvidersLocked();
221 updateProvidersLocked();
222 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700223
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700224 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700225 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700226 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700227 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800228 @Override
229 public void onChange(boolean selfChange) {
230 synchronized (mLock) {
231 updateProvidersLocked();
232 }
233 }
234 }, UserHandle.USER_ALL);
235 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700236
Victoria Lease38389b62012-09-30 11:44:22 -0700237 // listen for user change
238 IntentFilter intentFilter = new IntentFilter();
239 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
240
241 mContext.registerReceiverAsUser(new BroadcastReceiver() {
242 @Override
243 public void onReceive(Context context, Intent intent) {
244 String action = intent.getAction();
245 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
246 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
247 }
248 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800249 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700250 }
251
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500252 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
253 PackageManager pm = mContext.getPackageManager();
254 String systemPackageName = mContext.getPackageName();
255 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
256
257 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
258 new Intent(FUSED_LOCATION_SERVICE_ACTION),
259 PackageManager.GET_META_DATA, mCurrentUserId);
260 for (ResolveInfo rInfo : rInfos) {
261 String packageName = rInfo.serviceInfo.packageName;
262
263 // Check that the signature is in the list of supported sigs. If it's not in
264 // this list the standard provider binding logic won't bind to it.
265 try {
266 PackageInfo pInfo;
267 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
268 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
269 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
270 ", but has wrong signature, ignoring");
271 continue;
272 }
273 } catch (NameNotFoundException e) {
274 Log.e(TAG, "missing package: " + packageName);
275 continue;
276 }
277
278 // Get the version info
279 if (rInfo.serviceInfo.metaData == null) {
280 Log.w(TAG, "Found fused provider without metadata: " + packageName);
281 continue;
282 }
283
284 int version = rInfo.serviceInfo.metaData.getInt(
285 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
286 if (version == 0) {
287 // This should be the fallback fused location provider.
288
289 // Make sure it's in the system partition.
290 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
291 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
292 continue;
293 }
294
295 // Check that the fallback is signed the same as the OS
296 // as a proxy for coreApp="true"
297 if (pm.checkSignatures(systemPackageName, packageName)
298 != PackageManager.SIGNATURE_MATCH) {
299 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
300 + packageName);
301 continue;
302 }
303
304 // Found a valid fallback.
305 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
306 return;
307 } else {
308 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
309 }
310 }
311
312 throw new IllegalStateException("Unable to find a fused location provider that is in the "
313 + "system partition with version 0 and signed with the platform certificate. "
314 + "Such a package is needed to provide a default fused location provider in the "
315 + "event that no other fused location provider has been installed or is currently "
316 + "available. For example, coreOnly boot mode when decrypting the data "
317 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
318 }
319
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700320 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700321 // create a passive location provider, which is always enabled
322 PassiveProvider passiveProvider = new PassiveProvider(this);
323 addProviderLocked(passiveProvider);
324 mEnabledProviders.add(passiveProvider.getName());
325 mPassiveProvider = passiveProvider;
326
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700327 if (GpsLocationProvider.isSupported()) {
328 // Create a gps location provider
Victoria Lease5cd731a2012-12-19 15:04:21 -0800329 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
330 mLocationHandler.getLooper());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700331 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
332 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
333 addProviderLocked(gpsProvider);
334 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
335 }
336
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700337 /*
338 Load package name(s) containing location provider support.
339 These packages can contain services implementing location providers:
340 Geocoder Provider, Network Location Provider, and
341 Fused Location Provider. They will each be searched for
342 service components implementing these providers.
343 The location framework also has support for installation
344 of new location providers at run-time. The new package does not
345 have to be explicitly listed here, however it must have a signature
346 that matches the signature of at least one package on this list.
347 */
348 Resources resources = mContext.getResources();
349 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500350 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700351 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500352 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
353 Arrays.toString(pkgs));
354 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
355
356 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700357
358 // bind to network provider
359 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
360 mContext,
361 LocationManager.NETWORK_PROVIDER,
362 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700363 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700364 if (networkProvider != null) {
365 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
366 mProxyProviders.add(networkProvider);
367 addProviderLocked(networkProvider);
368 } else {
369 Slog.w(TAG, "no network location provider found");
370 }
371
372 // bind to fused provider
373 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
374 mContext,
375 LocationManager.FUSED_PROVIDER,
376 FUSED_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700377 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700378 if (fusedLocationProvider != null) {
379 addProviderLocked(fusedLocationProvider);
380 mProxyProviders.add(fusedLocationProvider);
381 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700382 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700383 } else {
384 Slog.e(TAG, "no fused location provider found",
385 new IllegalStateException("Location service needs a fused location provider"));
386 }
387
388 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700389 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
Victoria Lease5cd731a2012-12-19 15:04:21 -0800390 mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700391 if (mGeocodeProvider == null) {
392 Slog.e(TAG, "no geocoder provider found");
393 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700394 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700397 * Called when the device's active user changes.
398 * @param userId the new active user's UserId
399 */
400 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700401 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700402 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700403 mLastLocation.clear();
404 for (LocationProviderInterface p : mProviders) {
405 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Lease269518e2012-10-29 08:25:39 -0700406 p.switchUser(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700407 }
Victoria Lease38389b62012-09-30 11:44:22 -0700408 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700409 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700410 }
411 }
412
413 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
415 * location updates.
416 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700417 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700418 final int mUid; // uid of receiver
419 final int mPid; // pid of receiver
420 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700421 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 final ILocationListener mListener;
424 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700426
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400427 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700428
Mike Lockwood48f17512009-04-23 09:12:08 -0700429 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700431 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
432 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700435 if (listener != null) {
436 mKey = listener.asBinder();
437 } else {
438 mKey = intent;
439 }
Victoria Lease37425c32012-10-16 16:08:48 -0700440 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700441 mUid = uid;
442 mPid = pid;
443 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 }
445
446 @Override
447 public boolean equals(Object otherObj) {
448 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700449 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 }
451 return false;
452 }
453
454 @Override
455 public int hashCode() {
456 return mKey.hashCode();
457 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 @Override
460 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700461 StringBuilder s = new StringBuilder();
462 s.append("Reciever[");
463 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700465 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700467 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700469 for (String p : mUpdateRecords.keySet()) {
470 s.append(" ").append(mUpdateRecords.get(p).toString());
471 }
472 s.append("]");
473 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 }
475
476 public boolean isListener() {
477 return mListener != null;
478 }
479
480 public boolean isPendingIntent() {
481 return mPendingIntent != null;
482 }
483
484 public ILocationListener getListener() {
485 if (mListener != null) {
486 return mListener;
487 }
488 throw new IllegalStateException("Request for non-existent listener");
489 }
490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
492 if (mListener != null) {
493 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700494 synchronized (this) {
495 // synchronize to ensure incrementPendingBroadcastsLocked()
496 // is called before decrementPendingBroadcasts()
497 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700498 // call this after broadcasting so we do not increment
499 // if we throw an exeption.
500 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700501 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 } catch (RemoteException e) {
503 return false;
504 }
505 } else {
506 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800507 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
509 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700510 synchronized (this) {
511 // synchronize to ensure incrementPendingBroadcastsLocked()
512 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700513 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700514 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700515 // call this after broadcasting so we do not increment
516 // if we throw an exeption.
517 incrementPendingBroadcastsLocked();
518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 } catch (PendingIntent.CanceledException e) {
520 return false;
521 }
522 }
523 return true;
524 }
525
526 public boolean callLocationChangedLocked(Location location) {
527 if (mListener != null) {
528 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700529 synchronized (this) {
530 // synchronize to ensure incrementPendingBroadcastsLocked()
531 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800532 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700533 // call this after broadcasting so we do not increment
534 // if we throw an exeption.
535 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 } catch (RemoteException e) {
538 return false;
539 }
540 } else {
541 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800542 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700544 synchronized (this) {
545 // synchronize to ensure incrementPendingBroadcastsLocked()
546 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700547 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700548 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700549 // call this after broadcasting so we do not increment
550 // if we throw an exeption.
551 incrementPendingBroadcastsLocked();
552 }
553 } catch (PendingIntent.CanceledException e) {
554 return false;
555 }
556 }
557 return true;
558 }
559
560 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
561 if (mListener != null) {
562 try {
563 synchronized (this) {
564 // synchronize to ensure incrementPendingBroadcastsLocked()
565 // is called before decrementPendingBroadcasts()
566 if (enabled) {
567 mListener.onProviderEnabled(provider);
568 } else {
569 mListener.onProviderDisabled(provider);
570 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700571 // call this after broadcasting so we do not increment
572 // if we throw an exeption.
573 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700574 }
575 } catch (RemoteException e) {
576 return false;
577 }
578 } else {
579 Intent providerIntent = new Intent();
580 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
581 try {
582 synchronized (this) {
583 // synchronize to ensure incrementPendingBroadcastsLocked()
584 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700585 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700586 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700587 // call this after broadcasting so we do not increment
588 // if we throw an exeption.
589 incrementPendingBroadcastsLocked();
590 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 } catch (PendingIntent.CanceledException e) {
592 return false;
593 }
594 }
595 return true;
596 }
597
Nick Pellyf1be6862012-05-15 10:53:42 -0700598 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700600 if (D) Log.d(TAG, "Location listener died");
601
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400602 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 removeUpdatesLocked(this);
604 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700605 synchronized (this) {
606 if (mPendingBroadcasts > 0) {
607 LocationManagerService.this.decrementPendingBroadcasts();
608 mPendingBroadcasts = 0;
609 }
610 }
611 }
612
Nick Pellye0fd6932012-07-11 10:26:13 -0700613 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700614 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
615 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400616 synchronized (this) {
617 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700618 }
619 }
620
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400621 // this must be called while synchronized by caller in a synchronized block
622 // containing the sending of the broadcaset
623 private void incrementPendingBroadcastsLocked() {
624 if (mPendingBroadcasts++ == 0) {
625 LocationManagerService.this.incrementPendingBroadcasts();
626 }
627 }
628
629 private void decrementPendingBroadcastsLocked() {
630 if (--mPendingBroadcasts == 0) {
631 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700632 }
633 }
634 }
635
Nick Pellye0fd6932012-07-11 10:26:13 -0700636 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700637 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400638 //Do not use getReceiver here as that will add the ILocationListener to
639 //the receiver list if it is not found. If it is not found then the
640 //LocationListener was removed when it had a pending broadcast and should
641 //not be added back.
642 IBinder binder = listener.asBinder();
643 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700644 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400645 synchronized (receiver) {
646 // so wakelock calls will succeed
647 long identity = Binder.clearCallingIdentity();
648 receiver.decrementPendingBroadcastsLocked();
649 Binder.restoreCallingIdentity(identity);
650 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 }
652 }
653
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700654 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400655 mProviders.add(provider);
656 mProvidersByName.put(provider.getName(), provider);
657 }
658
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700659 private void removeProviderLocked(LocationProviderInterface provider) {
660 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400661 mProviders.remove(provider);
662 mProvidersByName.remove(provider.getName());
663 }
664
Mike Lockwood3d12b512009-04-21 23:25:35 -0700665
Victoria Lease269518e2012-10-29 08:25:39 -0700666 private boolean isAllowedBySettingsLocked(String provider, int userId) {
667 if (userId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700668 return false;
669 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 if (mEnabledProviders.contains(provider)) {
671 return true;
672 }
673 if (mDisabledProviders.contains(provider)) {
674 return false;
675 }
676 // Use system settings
677 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678
Victoria Leaseb711d572012-10-02 13:14:11 -0700679 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 }
681
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700682 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700683 * Returns the permission string associated with the specified resolution level.
684 *
685 * @param resolutionLevel the resolution level
686 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700687 */
Victoria Lease37425c32012-10-16 16:08:48 -0700688 private String getResolutionPermission(int resolutionLevel) {
689 switch (resolutionLevel) {
690 case RESOLUTION_LEVEL_FINE:
691 return android.Manifest.permission.ACCESS_FINE_LOCATION;
692 case RESOLUTION_LEVEL_COARSE:
693 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
694 default:
695 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700697 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700698
Victoria Leaseda479c52012-10-15 15:24:16 -0700699 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700700 * Returns the resolution level allowed to the given PID/UID pair.
701 *
702 * @param pid the PID
703 * @param uid the UID
704 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700705 */
Victoria Lease37425c32012-10-16 16:08:48 -0700706 private int getAllowedResolutionLevel(int pid, int uid) {
707 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
708 pid, uid) == PackageManager.PERMISSION_GRANTED) {
709 return RESOLUTION_LEVEL_FINE;
710 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
711 pid, uid) == PackageManager.PERMISSION_GRANTED) {
712 return RESOLUTION_LEVEL_COARSE;
713 } else {
714 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700715 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700716 }
717
718 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700719 * Returns the resolution level allowed to the caller
720 *
721 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700722 */
Victoria Lease37425c32012-10-16 16:08:48 -0700723 private int getCallerAllowedResolutionLevel() {
724 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
725 }
726
727 /**
728 * Throw SecurityException if specified resolution level is insufficient to use geofences.
729 *
730 * @param allowedResolutionLevel resolution level allowed to caller
731 */
732 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
733 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700734 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 }
737
Victoria Lease37425c32012-10-16 16:08:48 -0700738 /**
739 * Return the minimum resolution level required to use the specified location provider.
740 *
741 * @param provider the name of the location provider
742 * @return minimum resolution level required for provider
743 */
744 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700745 if (LocationManager.GPS_PROVIDER.equals(provider) ||
746 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
747 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700748 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700749 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
750 LocationManager.FUSED_PROVIDER.equals(provider)) {
751 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700752 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700753 } else {
754 // mock providers
755 LocationProviderInterface lp = mMockProviders.get(provider);
756 if (lp != null) {
757 ProviderProperties properties = lp.getProperties();
758 if (properties != null) {
759 if (properties.mRequiresSatellite) {
760 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700761 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700762 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
763 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700764 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700765 }
766 }
767 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700768 }
Victoria Lease37425c32012-10-16 16:08:48 -0700769 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700770 }
771
Victoria Lease37425c32012-10-16 16:08:48 -0700772 /**
773 * Throw SecurityException if specified resolution level is insufficient to use the named
774 * location provider.
775 *
776 * @param allowedResolutionLevel resolution level allowed to caller
777 * @param providerName the name of the location provider
778 */
779 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
780 String providerName) {
781 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
782 if (allowedResolutionLevel < requiredResolutionLevel) {
783 switch (requiredResolutionLevel) {
784 case RESOLUTION_LEVEL_FINE:
785 throw new SecurityException("\"" + providerName + "\" location provider " +
786 "requires ACCESS_FINE_LOCATION permission.");
787 case RESOLUTION_LEVEL_COARSE:
788 throw new SecurityException("\"" + providerName + "\" location provider " +
789 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
790 default:
791 throw new SecurityException("Insufficient permission for \"" + providerName +
792 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700793 }
794 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700795 }
796
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700797 /**
798 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700799 * fused, also including ones that are not permitted to
800 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700801 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700802 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700804 ArrayList<String> out;
805 synchronized (mLock) {
806 out = new ArrayList<String>(mProviders.size());
807 for (LocationProviderInterface provider : mProviders) {
808 String name = provider.getName();
809 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700810 continue;
811 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 out.add(name);
813 }
814 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700815
816 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 return out;
818 }
819
Mike Lockwood03ca2162010-04-01 08:10:09 -0700820 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700821 * Return all providers by name, that match criteria and are optionally
822 * enabled.
823 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700824 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700825 @Override
826 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700827 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700828 ArrayList<String> out;
Victoria Lease269518e2012-10-29 08:25:39 -0700829 int callingUserId = UserHandle.getCallingUserId();
830 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700831 try {
832 synchronized (mLock) {
833 out = new ArrayList<String>(mProviders.size());
834 for (LocationProviderInterface provider : mProviders) {
835 String name = provider.getName();
836 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700837 continue;
838 }
Victoria Lease37425c32012-10-16 16:08:48 -0700839 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease269518e2012-10-29 08:25:39 -0700840 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700841 continue;
842 }
843 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
844 name, provider.getProperties(), criteria)) {
845 continue;
846 }
847 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700848 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700849 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700850 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700851 } finally {
852 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700853 }
854
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700855 if (D) Log.d(TAG, "getProviders()=" + out);
856 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700857 }
858
859 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700860 * Return the name of the best provider given a Criteria object.
861 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700862 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700863 * has been deprecated as well. So this method now uses
864 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700865 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700866 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700867 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700868 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700869
870 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700871 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700872 result = pickBest(providers);
873 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
874 return result;
875 }
876 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700877 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700878 result = pickBest(providers);
879 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
880 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700881 }
882
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700883 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700884 return null;
885 }
886
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700887 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700888 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700889 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700890 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
891 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700892 } else {
893 return providers.get(0);
894 }
895 }
896
Nick Pellye0fd6932012-07-11 10:26:13 -0700897 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700898 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
899 LocationProviderInterface p = mProvidersByName.get(provider);
900 if (p == null) {
901 throw new IllegalArgumentException("provider=" + provider);
902 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700903
904 boolean result = LocationProvider.propertiesMeetCriteria(
905 p.getName(), p.getProperties(), criteria);
906 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
907 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700908 }
909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700911 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400912 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500913 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 boolean isEnabled = p.isEnabled();
915 String name = p.getName();
Victoria Lease269518e2012-10-29 08:25:39 -0700916 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700918 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700919 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700921 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700922 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700924 }
925 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700926 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
927 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 }
929 }
930
Victoria Leaseb711d572012-10-02 13:14:11 -0700931 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 int listeners = 0;
933
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500934 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700935 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936
937 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700938
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
940 if (records != null) {
941 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700942 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -0700944 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700945 // Sends a notification message to the receiver
946 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
947 if (deadReceivers == null) {
948 deadReceivers = new ArrayList<Receiver>();
949 }
950 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700952 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 }
955 }
956
957 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700958 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 removeUpdatesLocked(deadReceivers.get(i));
960 }
961 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700962
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 if (enabled) {
964 p.enable();
965 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700966 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 }
968 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 }
972
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700973 private void applyRequirementsLocked(String provider) {
974 LocationProviderInterface p = mProvidersByName.get(provider);
975 if (p == null) return;
976
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700978 WorkSource worksource = new WorkSource();
979 ProviderRequest providerRequest = new ProviderRequest();
980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700982 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -0700983 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700984 LocationRequest locationRequest = record.mRequest;
985 providerRequest.locationRequests.add(locationRequest);
986 if (locationRequest.getInterval() < providerRequest.interval) {
987 providerRequest.reportLocation = true;
988 providerRequest.interval = locationRequest.getInterval();
989 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700990 }
991 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700992
993 if (providerRequest.reportLocation) {
994 // calculate who to blame for power
995 // This is somewhat arbitrary. We pick a threshold interval
996 // that is slightly higher that the minimum interval, and
997 // spread the blame across all applications with a request
998 // under that threshold.
999 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1000 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001001 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001002 LocationRequest locationRequest = record.mRequest;
1003 if (locationRequest.getInterval() <= thresholdInterval) {
1004 worksource.add(record.mReceiver.mUid);
1005 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001006 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 }
1009 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001010
1011 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1012 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 }
1014
1015 private class UpdateRecord {
1016 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001017 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001019 Location mLastFixBroadcast;
1020 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021
1022 /**
1023 * Note: must be constructed with lock held.
1024 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001025 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001027 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029
1030 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1031 if (records == null) {
1032 records = new ArrayList<UpdateRecord>();
1033 mRecordsByProvider.put(provider, records);
1034 }
1035 if (!records.contains(this)) {
1036 records.add(this);
1037 }
1038 }
1039
1040 /**
1041 * Method to be called when a record will no longer be used. Calling this multiple times
1042 * must have the same effect as calling it once.
1043 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001044 void disposeLocked(boolean removeReceiver) {
1045 // remove from mRecordsByProvider
1046 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1047 if (globalRecords != null) {
1048 globalRecords.remove(this);
1049 }
1050
1051 if (!removeReceiver) return; // the caller will handle the rest
1052
1053 // remove from Receiver#mUpdateRecords
1054 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1055 if (receiverRecords != null) {
1056 receiverRecords.remove(this.mProvider);
1057
1058 // and also remove the Receiver if it has no more update records
1059 if (removeReceiver && receiverRecords.size() == 0) {
1060 removeUpdatesLocked(mReceiver);
1061 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001062 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 }
1064
1065 @Override
1066 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001067 StringBuilder s = new StringBuilder();
1068 s.append("UpdateRecord[");
1069 s.append(mProvider);
1070 s.append(' ').append(mReceiver.mPackageName).append('(');
1071 s.append(mReceiver.mUid).append(')');
1072 s.append(' ').append(mRequest);
1073 s.append(']');
1074 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 }
1077
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001078 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001079 IBinder binder = listener.asBinder();
1080 Receiver receiver = mReceivers.get(binder);
1081 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001082 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001083 mReceivers.put(binder, receiver);
1084
1085 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001086 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001087 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001088 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001089 return null;
1090 }
1091 }
1092 return receiver;
1093 }
1094
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001095 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001096 Receiver receiver = mReceivers.get(intent);
1097 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001098 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001099 mReceivers.put(intent, receiver);
1100 }
1101 return receiver;
1102 }
1103
Victoria Lease37425c32012-10-16 16:08:48 -07001104 /**
1105 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1106 * and consistency requirements.
1107 *
1108 * @param request the LocationRequest from which to create a sanitized version
1109 * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
1110 * constraints
1111 * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
1112 * @return a version of request that meets the given resolution and consistency requirements
1113 * @hide
1114 */
1115 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1116 LocationRequest sanitizedRequest = new LocationRequest(request);
1117 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1118 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001119 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001120 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001121 break;
1122 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001123 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001124 break;
1125 }
1126 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001127 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1128 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001129 }
Victoria Lease37425c32012-10-16 16:08:48 -07001130 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1131 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001132 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001133 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001134 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001135 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001136 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001137 }
Victoria Lease37425c32012-10-16 16:08:48 -07001138 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001139 }
1140
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001141 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001142 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001143 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001144 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001145 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001146 String[] packages = mPackageManager.getPackagesForUid(uid);
1147 if (packages == null) {
1148 throw new SecurityException("invalid UID " + uid);
1149 }
1150 for (String pkg : packages) {
1151 if (packageName.equals(pkg)) return;
1152 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001153 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001154 }
1155
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001156 private void checkPendingIntent(PendingIntent intent) {
1157 if (intent == null) {
1158 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001159 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001160 }
1161
1162 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1163 int pid, int uid, String packageName) {
1164 if (intent == null && listener == null) {
1165 throw new IllegalArgumentException("need eiter listener or intent");
1166 } else if (intent != null && listener != null) {
1167 throw new IllegalArgumentException("cannot register both listener and intent");
1168 } else if (intent != null) {
1169 checkPendingIntent(intent);
1170 return getReceiver(intent, pid, uid, packageName);
1171 } else {
1172 return getReceiver(listener, pid, uid, packageName);
1173 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001174 }
1175
Nick Pellye0fd6932012-07-11 10:26:13 -07001176 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001177 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1178 PendingIntent intent, String packageName) {
1179 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1180 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001181 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1182 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1183 request.getProvider());
1184 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001186 final int pid = Binder.getCallingPid();
1187 final int uid = Binder.getCallingUid();
1188 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001190 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 long identity = Binder.clearCallingIdentity();
1192 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001193 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001194 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 } finally {
1197 Binder.restoreCallingIdentity(identity);
1198 }
1199 }
1200
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001201 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1202 int pid, int uid, String packageName) {
1203 // Figure out the provider. Either its explicitly request (legacy use cases), or
1204 // use the fused provider
1205 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1206 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001207 if (name == null) {
1208 throw new IllegalArgumentException("provider name must not be null");
1209 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001210 LocationProviderInterface provider = mProvidersByName.get(name);
1211 if (provider == null) {
1212 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1213 }
1214
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001215 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1216 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001217
1218 UpdateRecord record = new UpdateRecord(name, request, receiver);
1219 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1220 if (oldRecord != null) {
1221 oldRecord.disposeLocked(false);
1222 }
1223
Victoria Lease269518e2012-10-29 08:25:39 -07001224 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001225 if (isProviderEnabled) {
1226 applyRequirementsLocked(name);
1227 } else {
1228 // Notify the listener that updates are currently disabled
1229 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 }
1231 }
1232
Nick Pellye0fd6932012-07-11 10:26:13 -07001233 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001234 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1235 String packageName) {
1236 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001237
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001238 final int pid = Binder.getCallingPid();
1239 final int uid = Binder.getCallingUid();
1240 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1241
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001242 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001243 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001245 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001246 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001248 } finally {
1249 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 }
1251 }
1252
1253 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001254 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001255
1256 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1257 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1258 synchronized (receiver) {
1259 if (receiver.mPendingBroadcasts > 0) {
1260 decrementPendingBroadcasts();
1261 receiver.mPendingBroadcasts = 0;
1262 }
1263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 }
1265
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001266 // Record which providers were associated with this listener
1267 HashSet<String> providers = new HashSet<String>();
1268 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1269 if (oldRecords != null) {
1270 // Call dispose() on the obsolete update records.
1271 for (UpdateRecord record : oldRecords.values()) {
1272 record.disposeLocked(false);
1273 }
1274 // Accumulate providers
1275 providers.addAll(oldRecords.keySet());
1276 }
1277
1278 // update provider
1279 for (String provider : providers) {
1280 // If provider is already disabled, don't need to do anything
Victoria Lease269518e2012-10-29 08:25:39 -07001281 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001282 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 }
1284
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001285 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 }
1287 }
1288
Nick Pellye0fd6932012-07-11 10:26:13 -07001289 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001290 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001291 if (D) Log.d(TAG, "getLastLocation: " + request);
1292 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001293 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001294 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001295 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1296 request.getProvider());
1297 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001298
Victoria Lease269518e2012-10-29 08:25:39 -07001299 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001300 try {
1301 if (mBlacklist.isBlacklisted(packageName)) {
1302 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1303 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001304 return null;
1305 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001306
1307 synchronized (mLock) {
1308 // Figure out the provider. Either its explicitly request (deprecated API's),
1309 // or use the fused provider
1310 String name = request.getProvider();
1311 if (name == null) name = LocationManager.FUSED_PROVIDER;
1312 LocationProviderInterface provider = mProvidersByName.get(name);
1313 if (provider == null) return null;
1314
Victoria Lease269518e2012-10-29 08:25:39 -07001315 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001316
1317 Location location = mLastLocation.get(name);
1318 if (location == null) {
1319 return null;
1320 }
Victoria Lease37425c32012-10-16 16:08:48 -07001321 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001322 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1323 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001324 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001325 }
Victoria Lease37425c32012-10-16 16:08:48 -07001326 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001327 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001328 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001329 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001330 return null;
1331 } finally {
1332 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001333 }
1334 }
1335
1336 @Override
1337 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1338 String packageName) {
1339 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001340 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1341 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001342 checkPendingIntent(intent);
1343 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001344 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1345 request.getProvider());
1346 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001347
Victoria Lease37425c32012-10-16 16:08:48 -07001348 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001349
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001350 // geo-fence manager uses the public location API, need to clear identity
1351 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001352 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1353 // temporary measure until geofences work for secondary users
1354 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1355 return;
1356 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001357 long identity = Binder.clearCallingIdentity();
1358 try {
Victoria Lease37425c32012-10-16 16:08:48 -07001359 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001360 } finally {
1361 Binder.restoreCallingIdentity(identity);
1362 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001363 }
1364
1365 @Override
1366 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001367 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001368 checkPendingIntent(intent);
1369 checkPackageName(packageName);
1370
1371 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1372
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001373 // geo-fence manager uses the public location API, need to clear identity
1374 long identity = Binder.clearCallingIdentity();
1375 try {
1376 mGeofenceManager.removeFence(geofence, intent);
1377 } finally {
1378 Binder.restoreCallingIdentity(identity);
1379 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001380 }
1381
1382
1383 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001385 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 return false;
1387 }
Victoria Lease37425c32012-10-16 16:08:48 -07001388 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1389 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390
1391 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001392 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001394 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 return false;
1396 }
1397 return true;
1398 }
1399
Nick Pellye0fd6932012-07-11 10:26:13 -07001400 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001402 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001403 try {
1404 mGpsStatusProvider.removeGpsStatusListener(listener);
1405 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001406 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001407 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 }
1409 }
1410
Nick Pellye0fd6932012-07-11 10:26:13 -07001411 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001413 if (provider == null) {
1414 // throw NullPointerException to remain compatible with previous implementation
1415 throw new NullPointerException();
1416 }
Victoria Lease37425c32012-10-16 16:08:48 -07001417 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1418 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001421 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 != PackageManager.PERMISSION_GRANTED)) {
1423 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1424 }
1425
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001426 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001427 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001428 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001429
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001430 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 }
1432 }
1433
Nick Pellye0fd6932012-07-11 10:26:13 -07001434 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001435 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001436 if (Binder.getCallingUid() != Process.myUid()) {
1437 throw new SecurityException(
1438 "calling sendNiResponse from outside of the system is not allowed");
1439 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001440 try {
1441 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001442 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001443 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001444 return false;
1445 }
1446 }
1447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001449 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001450 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 * accessed by the caller
1452 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001453 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001454 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001455 if (mProvidersByName.get(provider) == null) {
1456 return null;
1457 }
1458
Victoria Lease37425c32012-10-16 16:08:48 -07001459 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1460 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001462 LocationProviderInterface p;
1463 synchronized (mLock) {
1464 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 }
1466
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001467 if (p == null) return null;
1468 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 }
1470
Nick Pellye0fd6932012-07-11 10:26:13 -07001471 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001473 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1474 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001475 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1476
Victoria Lease269518e2012-10-29 08:25:39 -07001477 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001478 try {
1479 synchronized (mLock) {
1480 LocationProviderInterface p = mProvidersByName.get(provider);
1481 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001482
Victoria Lease269518e2012-10-29 08:25:39 -07001483 return isAllowedBySettingsLocked(provider, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -07001484 }
1485 } finally {
1486 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001487 }
1488 }
1489
1490 private void checkCallerIsProvider() {
1491 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1492 == PackageManager.PERMISSION_GRANTED) {
1493 return;
1494 }
1495
1496 // Previously we only used the INSTALL_LOCATION_PROVIDER
1497 // check. But that is system or signature
1498 // protection level which is not flexible enough for
1499 // providers installed oustide the system image. So
1500 // also allow providers with a UID matching the
1501 // currently bound package name
1502
1503 int uid = Binder.getCallingUid();
1504
1505 if (mGeocodeProvider != null) {
1506 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1507 }
1508 for (LocationProviderProxy proxy : mProxyProviders) {
1509 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1510 }
1511 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1512 "or UID of a currently bound location provider");
1513 }
1514
1515 private boolean doesPackageHaveUid(int uid, String packageName) {
1516 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 return false;
1518 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001519 try {
1520 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1521 if (appInfo.uid != uid) {
1522 return false;
1523 }
1524 } catch (NameNotFoundException e) {
1525 return false;
1526 }
1527 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 }
1529
Nick Pellye0fd6932012-07-11 10:26:13 -07001530 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001531 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001532 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001533
Nick Pelly2eeeec22012-07-18 13:13:37 -07001534 if (!location.isComplete()) {
1535 Log.w(TAG, "Dropping incomplete location: " + location);
1536 return;
1537 }
1538
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001539 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1540 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001541 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001542 mLocationHandler.sendMessageAtFrontOfQueue(m);
1543 }
1544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545
Laurent Tu75defb62012-11-01 16:21:52 -07001546 private static boolean shouldBroadcastSafe(
1547 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 // Always broadcast the first update
1549 if (lastLoc == null) {
1550 return true;
1551 }
1552
Nick Pellyf1be6862012-05-15 10:53:42 -07001553 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001554 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001555 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001556 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 return false;
1558 }
1559
1560 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001561 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 if (minDistance > 0.0) {
1563 if (loc.distanceTo(lastLoc) <= minDistance) {
1564 return false;
1565 }
1566 }
1567
Laurent Tu75defb62012-11-01 16:21:52 -07001568 // Check whether sufficient number of udpates is left
1569 if (record.mRequest.getNumUpdates() <= 0) {
1570 return false;
1571 }
1572
1573 // Check whether the expiry date has passed
1574 if (record.mRequest.getExpireAt() < now) {
1575 return false;
1576 }
1577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 return true;
1579 }
1580
Mike Lockwooda4903f22010-02-17 06:42:23 -05001581 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001582 if (D) Log.d(TAG, "incoming location: " + location);
1583
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001584 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001585 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586
Laurent Tu60ec50a2012-10-04 17:00:10 -07001587 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001588 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001589 if (p == null) return;
1590
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001591 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001592 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1593 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001594 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001595 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001596 lastLocation = new Location(provider);
1597 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001598 } else {
1599 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1600 if (noGPSLocation == null && lastNoGPSLocation != null) {
1601 // New location has no no-GPS location: adopt last no-GPS location. This is set
1602 // directly into location because we do not want to notify COARSE clients.
1603 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1604 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001605 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001606 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607
Laurent Tu60ec50a2012-10-04 17:00:10 -07001608 // Skip if there are no UpdateRecords for this provider.
1609 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1610 if (records == null || records.size() == 0) return;
1611
Victoria Lease09016ab2012-09-16 12:33:15 -07001612 // Fetch coarse location
1613 Location coarseLocation = null;
1614 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1615 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1616 }
1617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001618 // Fetch latest status update time
1619 long newStatusUpdateTime = p.getStatusUpdateTime();
1620
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001621 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 Bundle extras = new Bundle();
1623 int status = p.getStatus(extras);
1624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001626 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001629 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001631 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001632
Victoria Lease269518e2012-10-29 08:25:39 -07001633 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1634 if (receiverUserId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001635 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001636 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001637 " (current user: " + mCurrentUserId + ", app: " +
1638 receiver.mPackageName + ")");
1639 }
1640 continue;
1641 }
1642
Nick Pelly4035f5a2012-08-17 14:43:49 -07001643 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1644 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1645 receiver.mPackageName);
1646 continue;
1647 }
1648
Victoria Lease09016ab2012-09-16 12:33:15 -07001649 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001650 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1651 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001652 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001653 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001654 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001655 if (notifyLocation != null) {
1656 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001657 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001658 if (lastLoc == null) {
1659 lastLoc = new Location(notifyLocation);
1660 r.mLastFixBroadcast = lastLoc;
1661 } else {
1662 lastLoc.set(notifyLocation);
1663 }
1664 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1665 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1666 receiverDead = true;
1667 }
Laurent Tu75defb62012-11-01 16:21:52 -07001668 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 }
1670 }
1671
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001672 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001674 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001676 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001678 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001679 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001680 }
1681 }
1682
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001683 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001684 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001685 if (deadUpdateRecords == null) {
1686 deadUpdateRecords = new ArrayList<UpdateRecord>();
1687 }
1688 deadUpdateRecords.add(r);
1689 }
1690 // track dead receivers
1691 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001692 if (deadReceivers == null) {
1693 deadReceivers = new ArrayList<Receiver>();
1694 }
1695 if (!deadReceivers.contains(receiver)) {
1696 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 }
1698 }
1699 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001700
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001701 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001703 for (Receiver receiver : deadReceivers) {
1704 removeUpdatesLocked(receiver);
1705 }
1706 }
1707 if (deadUpdateRecords != null) {
1708 for (UpdateRecord r : deadUpdateRecords) {
1709 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 }
Victoria Lease8b38b292012-12-04 15:04:43 -08001711 applyRequirementsLocked(provider);
1712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 }
1714
1715 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001716 public LocationWorkerHandler(Looper looper) {
1717 super(looper, null, true);
1718 }
1719
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 @Override
1721 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001722 switch (msg.what) {
1723 case MSG_LOCATION_CHANGED:
1724 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1725 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 }
1727 }
1728 }
1729
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001730 private void handleLocationChanged(Location location, boolean passive) {
1731 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001732
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001733 if (!passive) {
1734 // notify passive provider of the new location
1735 mPassiveProvider.updateLocation(location);
1736 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001738 synchronized (mLock) {
Victoria Lease269518e2012-10-29 08:25:39 -07001739 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001740 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001743 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744
Mike Lockwoode97ae402010-09-29 15:23:46 -04001745 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1746 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001747 public void onPackageDisappeared(String packageName, int reason) {
1748 // remove all receivers associated with this package name
1749 synchronized (mLock) {
1750 ArrayList<Receiver> deadReceivers = null;
1751
1752 for (Receiver receiver : mReceivers.values()) {
1753 if (receiver.mPackageName.equals(packageName)) {
1754 if (deadReceivers == null) {
1755 deadReceivers = new ArrayList<Receiver>();
1756 }
1757 deadReceivers.add(receiver);
1758 }
1759 }
1760
1761 // perform removal outside of mReceivers loop
1762 if (deadReceivers != null) {
1763 for (Receiver receiver : deadReceivers) {
1764 removeUpdatesLocked(receiver);
1765 }
1766 }
1767 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001768 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001769 };
1770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 // Wake locks
1772
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001773 private void incrementPendingBroadcasts() {
1774 synchronized (mWakeLock) {
1775 if (mPendingBroadcasts++ == 0) {
1776 try {
1777 mWakeLock.acquire();
1778 log("Acquired wakelock");
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 acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001783 }
1784 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001785 }
1786 }
1787
1788 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001789 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001790 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001791 try {
1792 // Release wake lock
1793 if (mWakeLock.isHeld()) {
1794 mWakeLock.release();
1795 log("Released wakelock");
1796 } else {
1797 log("Can't release wakelock again!");
1798 }
1799 } catch (Exception e) {
1800 // This is to catch a runtime exception thrown when we try to release an
1801 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001802 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001803 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001804 }
1805 }
1806 }
1807
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 // Geocoder
1809
Nick Pellye0fd6932012-07-11 10:26:13 -07001810 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001811 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001812 return mGeocodeProvider != null;
1813 }
1814
Nick Pellye0fd6932012-07-11 10:26:13 -07001815 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001816 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001817 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001818 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001819 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1820 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001822 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 }
1824
Mike Lockwooda55c3212009-04-15 11:10:11 -04001825
Nick Pellye0fd6932012-07-11 10:26:13 -07001826 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001827 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001828 double lowerLeftLatitude, double lowerLeftLongitude,
1829 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001830 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001831
1832 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001833 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1834 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1835 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001837 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 }
1839
1840 // Mock Providers
1841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 private void checkMockPermissionsSafe() {
1843 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1844 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1845 if (!allowMocks) {
1846 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1847 }
1848
1849 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1850 PackageManager.PERMISSION_GRANTED) {
1851 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 }
1854
Nick Pellye0fd6932012-07-11 10:26:13 -07001855 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001856 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 checkMockPermissionsSafe();
1858
Mike Lockwooda4903f22010-02-17 06:42:23 -05001859 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1860 throw new IllegalArgumentException("Cannot mock the passive location provider");
1861 }
1862
Mike Lockwood86328a92009-10-23 08:38:25 -04001863 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001864 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001865 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001866 // remove the real provider if we are replacing GPS or network provider
1867 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001868 || LocationManager.NETWORK_PROVIDER.equals(name)
1869 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001870 LocationProviderInterface p = mProvidersByName.get(name);
1871 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001872 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001873 }
1874 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001875 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1877 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001878 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001879 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001880 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 updateProvidersLocked();
1882 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001883 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 }
1885
Nick Pellye0fd6932012-07-11 10:26:13 -07001886 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 public void removeTestProvider(String provider) {
1888 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001889 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09001890 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001891 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1893 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001894 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001895 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001896
1897 // reinstate real provider if available
1898 LocationProviderInterface realProvider = mRealProviders.get(provider);
1899 if (realProvider != null) {
1900 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001901 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001902 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001903 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001904 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 }
1906 }
1907
Nick Pellye0fd6932012-07-11 10:26:13 -07001908 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909 public void setTestProviderLocation(String provider, Location loc) {
1910 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001911 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001912 MockProvider mockProvider = mMockProviders.get(provider);
1913 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001914 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1915 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001916 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1917 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001918 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001919 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 }
1921 }
1922
Nick Pellye0fd6932012-07-11 10:26:13 -07001923 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 public void clearTestProviderLocation(String provider) {
1925 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001926 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001927 MockProvider mockProvider = mMockProviders.get(provider);
1928 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1930 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001931 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001932 }
1933 }
1934
Nick Pellye0fd6932012-07-11 10:26:13 -07001935 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001936 public void setTestProviderEnabled(String provider, boolean enabled) {
1937 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001938 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001939 MockProvider mockProvider = mMockProviders.get(provider);
1940 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1942 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001943 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001944 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001945 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001946 mEnabledProviders.add(provider);
1947 mDisabledProviders.remove(provider);
1948 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001949 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001950 mEnabledProviders.remove(provider);
1951 mDisabledProviders.add(provider);
1952 }
1953 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001954 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 }
1956 }
1957
Nick Pellye0fd6932012-07-11 10:26:13 -07001958 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 public void clearTestProviderEnabled(String provider) {
1960 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001961 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001962 MockProvider mockProvider = mMockProviders.get(provider);
1963 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001964 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1965 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001966 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 mEnabledProviders.remove(provider);
1968 mDisabledProviders.remove(provider);
1969 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001970 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 }
1972 }
1973
Nick Pellye0fd6932012-07-11 10:26:13 -07001974 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1976 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001977 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001978 MockProvider mockProvider = mMockProviders.get(provider);
1979 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1981 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001982 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 }
1984 }
1985
Nick Pellye0fd6932012-07-11 10:26:13 -07001986 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 public void clearTestProviderStatus(String provider) {
1988 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001989 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001990 MockProvider mockProvider = mMockProviders.get(provider);
1991 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1993 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001994 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001995 }
1996 }
1997
1998 private void log(String log) {
1999 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002000 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002001 }
2002 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002003
2004 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2006 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2007 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002008 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 + Binder.getCallingPid()
2010 + ", uid=" + Binder.getCallingUid());
2011 return;
2012 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002013
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002014 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002016 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002017 for (Receiver receiver : mReceivers.values()) {
2018 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002021 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2022 pw.println(" " + entry.getKey() + ":");
2023 for (UpdateRecord record : entry.getValue()) {
2024 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 }
2026 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002027 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002028 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2029 String provider = entry.getKey();
2030 Location location = entry.getValue();
2031 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002033
Nick Pellye0fd6932012-07-11 10:26:13 -07002034 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 if (mEnabledProviders.size() > 0) {
2037 pw.println(" Enabled Providers:");
2038 for (String i : mEnabledProviders) {
2039 pw.println(" " + i);
2040 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002041
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002042 }
2043 if (mDisabledProviders.size() > 0) {
2044 pw.println(" Disabled Providers:");
2045 for (String i : mDisabledProviders) {
2046 pw.println(" " + i);
2047 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002049 pw.append(" ");
2050 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 if (mMockProviders.size() > 0) {
2052 pw.println(" Mock Providers:");
2053 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002054 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055 }
2056 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002057
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002058 pw.append(" fudger: ");
2059 mLocationFudger.dump(fd, pw, args);
2060
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002061 if (args.length > 0 && "short".equals(args[0])) {
2062 return;
2063 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002064 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002065 pw.print(provider.getName() + " Internal State");
2066 if (provider instanceof LocationProviderProxy) {
2067 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2068 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002069 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002070 pw.println(":");
2071 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002072 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 }
2074 }
2075}