blob: f21f826d9fd8f8616d07733c38b0e84a537ad2ad [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070020import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070024import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050026import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070028import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050029import android.content.pm.ResolveInfo;
30import android.content.pm.Signature;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050031import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070032import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070034import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050035import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070036import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040038import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.ILocationListener;
40import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040041import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.location.Location;
43import android.location.LocationManager;
44import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070045import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.Binder;
47import android.os.Bundle;
48import android.os.Handler;
49import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070050import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.Message;
52import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070053import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070055import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070056import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070057import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080060import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
Mike Lockwoode97ae402010-09-29 15:23:46 -040062import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070063import com.android.internal.location.ProviderProperties;
64import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040065import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070066import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040067import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070068import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070069import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040070import com.android.server.location.LocationProviderInterface;
71import com.android.server.location.LocationProviderProxy;
72import com.android.server.location.MockProvider;
73import com.android.server.location.PassiveProvider;
74
75import java.io.FileDescriptor;
76import java.io.PrintWriter;
77import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070078import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040079import java.util.HashMap;
80import java.util.HashSet;
81import java.util.List;
82import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040083import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
85/**
86 * The service class that manages LocationProviders and issues location
87 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 */
Brian Muramatsubb95cb92012-08-29 10:43:21 -070089public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070091 public static final boolean D = false;
92
93 private static final String WAKELOCK_KEY = TAG;
94 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
Victoria Lease37425c32012-10-16 16:08:48 -070096 // Location resolution level: no location data whatsoever
97 private static final int RESOLUTION_LEVEL_NONE = 0;
98 // Location resolution level: coarse location data only
99 private static final int RESOLUTION_LEVEL_COARSE = 1;
100 // Location resolution level: fine location data
101 private static final int RESOLUTION_LEVEL_FINE = 2;
102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700104 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700106 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400107 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700108 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
109
110 private static final String NETWORK_LOCATION_SERVICE_ACTION =
111 "com.android.location.service.v2.NetworkLocationProvider";
112 private static final String FUSED_LOCATION_SERVICE_ACTION =
113 "com.android.location.service.FusedLocationProvider";
114
115 private static final int MSG_LOCATION_CHANGED = 1;
116
Nick Pellyf1be6862012-05-15 10:53:42 -0700117 // Location Providers may sometimes deliver location updates
118 // slightly faster that requested - provide grace period so
119 // we don't unnecessarily filter events that are otherwise on
120 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700121 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700122
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700123 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
124
125 private final Context mContext;
126
127 // used internally for synchronization
128 private final Object mLock = new Object();
129
130 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700131 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700132 private GeofenceManager mGeofenceManager;
133 private PowerManager.WakeLock mWakeLock;
134 private PackageManager mPackageManager;
135 private GeocoderProxy mGeocodeProvider;
136 private IGpsStatusProvider mGpsStatusProvider;
137 private INetInitiatedListener mNetInitiatedListener;
138 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700139 private PassiveProvider mPassiveProvider; // track passive provider for special cases
140 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700141
142 // --- fields below are protected by mWakeLock ---
143 private int mPendingBroadcasts;
144
145 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 // Set of providers that are explicitly enabled
147 private final Set<String> mEnabledProviders = new HashSet<String>();
148
149 // Set of providers that are explicitly disabled
150 private final Set<String> mDisabledProviders = new HashSet<String>();
151
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700152 // Mock (test) providers
153 private final HashMap<String, MockProvider> mMockProviders =
154 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700156 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400157 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700159 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500160 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700161 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400162
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700163 // real providers, saved here when mocked out
164 private final HashMap<String, LocationProviderInterface> mRealProviders =
165 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 // mapping from provider name to provider
168 private final HashMap<String, LocationProviderInterface> mProvidersByName =
169 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700171 // mapping from provider name to all its UpdateRecords
172 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
173 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700174
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700175 // mapping from provider name to last known location
176 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700178 // all providers that operate over proxy, for authorizing incoming location
179 private final ArrayList<LocationProviderProxy> mProxyProviders =
180 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181
Victoria Lease38389b62012-09-30 11:44:22 -0700182 // current active user on the device - other users are denied location data
183 private int mCurrentUserId = UserHandle.USER_OWNER;
184
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 public LocationManagerService(Context context) {
186 super();
187 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800188
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700189 if (D) Log.d(TAG, "Constructed");
190
191 // most startup is deferred until systemReady()
192 }
193
194 public void systemReady() {
195 Thread thread = new Thread(null, this, THREAD_NAME);
196 thread.start();
197 }
198
199 @Override
200 public void run() {
201 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
202 Looper.prepare();
203 mLocationHandler = new LocationWorkerHandler();
204 init();
205 Looper.loop();
206 }
207
208 private void init() {
209 if (D) Log.d(TAG, "init()");
210
211 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
212 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
213 mPackageManager = mContext.getPackageManager();
214
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700215 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
216 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700217 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700218
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700219 synchronized (mLock) {
220 loadProvidersLocked();
221 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700222
Nick Pelly4035f5a2012-08-17 14:43:49 -0700223 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700224
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700225 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700226 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700227 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700228 new ContentObserver(mLocationHandler) {
229 @Override
230 public void onChange(boolean selfChange) {
231 synchronized (mLock) {
232 updateProvidersLocked();
233 }
234 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700235 }, UserHandle.USER_ALL);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700236 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700237
Victoria Lease38389b62012-09-30 11:44:22 -0700238 // listen for user change
239 IntentFilter intentFilter = new IntentFilter();
240 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
241
242 mContext.registerReceiverAsUser(new BroadcastReceiver() {
243 @Override
244 public void onReceive(Context context, Intent intent) {
245 String action = intent.getAction();
246 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
247 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
248 }
249 }
250 }, UserHandle.ALL, intentFilter, null, null);
251
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700252 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700253 }
254
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500255 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
256 PackageManager pm = mContext.getPackageManager();
257 String systemPackageName = mContext.getPackageName();
258 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
259
260 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
261 new Intent(FUSED_LOCATION_SERVICE_ACTION),
262 PackageManager.GET_META_DATA, mCurrentUserId);
263 for (ResolveInfo rInfo : rInfos) {
264 String packageName = rInfo.serviceInfo.packageName;
265
266 // Check that the signature is in the list of supported sigs. If it's not in
267 // this list the standard provider binding logic won't bind to it.
268 try {
269 PackageInfo pInfo;
270 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
271 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
272 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
273 ", but has wrong signature, ignoring");
274 continue;
275 }
276 } catch (NameNotFoundException e) {
277 Log.e(TAG, "missing package: " + packageName);
278 continue;
279 }
280
281 // Get the version info
282 if (rInfo.serviceInfo.metaData == null) {
283 Log.w(TAG, "Found fused provider without metadata: " + packageName);
284 continue;
285 }
286
287 int version = rInfo.serviceInfo.metaData.getInt(
288 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
289 if (version == 0) {
290 // This should be the fallback fused location provider.
291
292 // Make sure it's in the system partition.
293 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
294 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
295 continue;
296 }
297
298 // Check that the fallback is signed the same as the OS
299 // as a proxy for coreApp="true"
300 if (pm.checkSignatures(systemPackageName, packageName)
301 != PackageManager.SIGNATURE_MATCH) {
302 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
303 + packageName);
304 continue;
305 }
306
307 // Found a valid fallback.
308 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
309 return;
310 } else {
311 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
312 }
313 }
314
315 throw new IllegalStateException("Unable to find a fused location provider that is in the "
316 + "system partition with version 0 and signed with the platform certificate. "
317 + "Such a package is needed to provide a default fused location provider in the "
318 + "event that no other fused location provider has been installed or is currently "
319 + "available. For example, coreOnly boot mode when decrypting the data "
320 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
321 }
322
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700323 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700324 // create a passive location provider, which is always enabled
325 PassiveProvider passiveProvider = new PassiveProvider(this);
326 addProviderLocked(passiveProvider);
327 mEnabledProviders.add(passiveProvider.getName());
328 mPassiveProvider = passiveProvider;
329
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700330 if (GpsLocationProvider.isSupported()) {
331 // Create a gps location provider
332 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
333 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
334 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
335 addProviderLocked(gpsProvider);
336 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
337 }
338
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700339 /*
340 Load package name(s) containing location provider support.
341 These packages can contain services implementing location providers:
342 Geocoder Provider, Network Location Provider, and
343 Fused Location Provider. They will each be searched for
344 service components implementing these providers.
345 The location framework also has support for installation
346 of new location providers at run-time. The new package does not
347 have to be explicitly listed here, however it must have a signature
348 that matches the signature of at least one package on this list.
349 */
350 Resources resources = mContext.getResources();
351 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500352 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700353 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500354 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
355 Arrays.toString(pkgs));
356 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
357
358 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700359
360 // bind to network provider
361 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
362 mContext,
363 LocationManager.NETWORK_PROVIDER,
364 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700365 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700366 if (networkProvider != null) {
367 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
368 mProxyProviders.add(networkProvider);
369 addProviderLocked(networkProvider);
370 } else {
371 Slog.w(TAG, "no network location provider found");
372 }
373
374 // bind to fused provider
375 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
376 mContext,
377 LocationManager.FUSED_PROVIDER,
378 FUSED_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700379 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700380 if (fusedLocationProvider != null) {
381 addProviderLocked(fusedLocationProvider);
382 mProxyProviders.add(fusedLocationProvider);
383 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700384 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700385 } else {
386 Slog.e(TAG, "no fused location provider found",
387 new IllegalStateException("Location service needs a fused location provider"));
388 }
389
390 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700391 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
392 mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700393 if (mGeocodeProvider == null) {
394 Slog.e(TAG, "no geocoder provider found");
395 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700396 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700399 * Called when the device's active user changes.
400 * @param userId the new active user's UserId
401 */
402 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700403 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700404 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700405 mLastLocation.clear();
406 for (LocationProviderInterface p : mProviders) {
407 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Lease269518e2012-10-29 08:25:39 -0700408 p.switchUser(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700409 }
Victoria Lease38389b62012-09-30 11:44:22 -0700410 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700411 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700412 }
413 }
414
415 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
417 * location updates.
418 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700419 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700420 final int mUid; // uid of receiver
421 final int mPid; // pid of receiver
422 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700423 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 final ILocationListener mListener;
426 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700428
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400429 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700430
Mike Lockwood48f17512009-04-23 09:12:08 -0700431 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700433 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
434 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700437 if (listener != null) {
438 mKey = listener.asBinder();
439 } else {
440 mKey = intent;
441 }
Victoria Lease37425c32012-10-16 16:08:48 -0700442 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700443 mUid = uid;
444 mPid = pid;
445 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 }
447
448 @Override
449 public boolean equals(Object otherObj) {
450 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700451 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 }
453 return false;
454 }
455
456 @Override
457 public int hashCode() {
458 return mKey.hashCode();
459 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 @Override
462 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700463 StringBuilder s = new StringBuilder();
464 s.append("Reciever[");
465 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700467 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700469 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700471 for (String p : mUpdateRecords.keySet()) {
472 s.append(" ").append(mUpdateRecords.get(p).toString());
473 }
474 s.append("]");
475 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 }
477
478 public boolean isListener() {
479 return mListener != null;
480 }
481
482 public boolean isPendingIntent() {
483 return mPendingIntent != null;
484 }
485
486 public ILocationListener getListener() {
487 if (mListener != null) {
488 return mListener;
489 }
490 throw new IllegalStateException("Request for non-existent listener");
491 }
492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
494 if (mListener != null) {
495 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700496 synchronized (this) {
497 // synchronize to ensure incrementPendingBroadcastsLocked()
498 // is called before decrementPendingBroadcasts()
499 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700500 // call this after broadcasting so we do not increment
501 // if we throw an exeption.
502 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 } catch (RemoteException e) {
505 return false;
506 }
507 } else {
508 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800509 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
511 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700512 synchronized (this) {
513 // synchronize to ensure incrementPendingBroadcastsLocked()
514 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700515 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700516 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700517 // call this after broadcasting so we do not increment
518 // if we throw an exeption.
519 incrementPendingBroadcastsLocked();
520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 } catch (PendingIntent.CanceledException e) {
522 return false;
523 }
524 }
525 return true;
526 }
527
528 public boolean callLocationChangedLocked(Location location) {
529 if (mListener != null) {
530 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700531 synchronized (this) {
532 // synchronize to ensure incrementPendingBroadcastsLocked()
533 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800534 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700535 // call this after broadcasting so we do not increment
536 // if we throw an exeption.
537 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 } catch (RemoteException e) {
540 return false;
541 }
542 } else {
543 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800544 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700546 synchronized (this) {
547 // synchronize to ensure incrementPendingBroadcastsLocked()
548 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700549 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700550 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700551 // call this after broadcasting so we do not increment
552 // if we throw an exeption.
553 incrementPendingBroadcastsLocked();
554 }
555 } catch (PendingIntent.CanceledException e) {
556 return false;
557 }
558 }
559 return true;
560 }
561
562 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
563 if (mListener != null) {
564 try {
565 synchronized (this) {
566 // synchronize to ensure incrementPendingBroadcastsLocked()
567 // is called before decrementPendingBroadcasts()
568 if (enabled) {
569 mListener.onProviderEnabled(provider);
570 } else {
571 mListener.onProviderDisabled(provider);
572 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700573 // call this after broadcasting so we do not increment
574 // if we throw an exeption.
575 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700576 }
577 } catch (RemoteException e) {
578 return false;
579 }
580 } else {
581 Intent providerIntent = new Intent();
582 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
583 try {
584 synchronized (this) {
585 // synchronize to ensure incrementPendingBroadcastsLocked()
586 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700587 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700588 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700589 // call this after broadcasting so we do not increment
590 // if we throw an exeption.
591 incrementPendingBroadcastsLocked();
592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 } catch (PendingIntent.CanceledException e) {
594 return false;
595 }
596 }
597 return true;
598 }
599
Nick Pellyf1be6862012-05-15 10:53:42 -0700600 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700602 if (D) Log.d(TAG, "Location listener died");
603
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400604 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 removeUpdatesLocked(this);
606 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700607 synchronized (this) {
608 if (mPendingBroadcasts > 0) {
609 LocationManagerService.this.decrementPendingBroadcasts();
610 mPendingBroadcasts = 0;
611 }
612 }
613 }
614
Nick Pellye0fd6932012-07-11 10:26:13 -0700615 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700616 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
617 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400618 synchronized (this) {
619 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700620 }
621 }
622
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400623 // this must be called while synchronized by caller in a synchronized block
624 // containing the sending of the broadcaset
625 private void incrementPendingBroadcastsLocked() {
626 if (mPendingBroadcasts++ == 0) {
627 LocationManagerService.this.incrementPendingBroadcasts();
628 }
629 }
630
631 private void decrementPendingBroadcastsLocked() {
632 if (--mPendingBroadcasts == 0) {
633 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700634 }
635 }
636 }
637
Nick Pellye0fd6932012-07-11 10:26:13 -0700638 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700639 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400640 //Do not use getReceiver here as that will add the ILocationListener to
641 //the receiver list if it is not found. If it is not found then the
642 //LocationListener was removed when it had a pending broadcast and should
643 //not be added back.
644 IBinder binder = listener.asBinder();
645 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700646 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400647 synchronized (receiver) {
648 // so wakelock calls will succeed
649 long identity = Binder.clearCallingIdentity();
650 receiver.decrementPendingBroadcastsLocked();
651 Binder.restoreCallingIdentity(identity);
652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654 }
655
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700656 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400657 mProviders.add(provider);
658 mProvidersByName.put(provider.getName(), provider);
659 }
660
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 private void removeProviderLocked(LocationProviderInterface provider) {
662 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400663 mProviders.remove(provider);
664 mProvidersByName.remove(provider.getName());
665 }
666
Mike Lockwood3d12b512009-04-21 23:25:35 -0700667
Victoria Lease269518e2012-10-29 08:25:39 -0700668 private boolean isAllowedBySettingsLocked(String provider, int userId) {
669 if (userId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700670 return false;
671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 if (mEnabledProviders.contains(provider)) {
673 return true;
674 }
675 if (mDisabledProviders.contains(provider)) {
676 return false;
677 }
678 // Use system settings
679 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680
Victoria Leaseb711d572012-10-02 13:14:11 -0700681 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 }
683
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700684 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700685 * Returns the permission string associated with the specified resolution level.
686 *
687 * @param resolutionLevel the resolution level
688 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700689 */
Victoria Lease37425c32012-10-16 16:08:48 -0700690 private String getResolutionPermission(int resolutionLevel) {
691 switch (resolutionLevel) {
692 case RESOLUTION_LEVEL_FINE:
693 return android.Manifest.permission.ACCESS_FINE_LOCATION;
694 case RESOLUTION_LEVEL_COARSE:
695 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
696 default:
697 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700699 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700700
Victoria Leaseda479c52012-10-15 15:24:16 -0700701 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700702 * Returns the resolution level allowed to the given PID/UID pair.
703 *
704 * @param pid the PID
705 * @param uid the UID
706 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700707 */
Victoria Lease37425c32012-10-16 16:08:48 -0700708 private int getAllowedResolutionLevel(int pid, int uid) {
709 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
710 pid, uid) == PackageManager.PERMISSION_GRANTED) {
711 return RESOLUTION_LEVEL_FINE;
712 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
713 pid, uid) == PackageManager.PERMISSION_GRANTED) {
714 return RESOLUTION_LEVEL_COARSE;
715 } else {
716 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700717 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700718 }
719
720 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700721 * Returns the resolution level allowed to the caller
722 *
723 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700724 */
Victoria Lease37425c32012-10-16 16:08:48 -0700725 private int getCallerAllowedResolutionLevel() {
726 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
727 }
728
729 /**
730 * Throw SecurityException if specified resolution level is insufficient to use geofences.
731 *
732 * @param allowedResolutionLevel resolution level allowed to caller
733 */
734 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
735 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700736 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 }
739
Victoria Lease37425c32012-10-16 16:08:48 -0700740 /**
741 * Return the minimum resolution level required to use the specified location provider.
742 *
743 * @param provider the name of the location provider
744 * @return minimum resolution level required for provider
745 */
746 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700747 if (LocationManager.GPS_PROVIDER.equals(provider) ||
748 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
749 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700750 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700751 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
752 LocationManager.FUSED_PROVIDER.equals(provider)) {
753 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700754 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700755 } else {
756 // mock providers
757 LocationProviderInterface lp = mMockProviders.get(provider);
758 if (lp != null) {
759 ProviderProperties properties = lp.getProperties();
760 if (properties != null) {
761 if (properties.mRequiresSatellite) {
762 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700763 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700764 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
765 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700766 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700767 }
768 }
769 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700770 }
Victoria Lease37425c32012-10-16 16:08:48 -0700771 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700772 }
773
Victoria Lease37425c32012-10-16 16:08:48 -0700774 /**
775 * Throw SecurityException if specified resolution level is insufficient to use the named
776 * location provider.
777 *
778 * @param allowedResolutionLevel resolution level allowed to caller
779 * @param providerName the name of the location provider
780 */
781 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
782 String providerName) {
783 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
784 if (allowedResolutionLevel < requiredResolutionLevel) {
785 switch (requiredResolutionLevel) {
786 case RESOLUTION_LEVEL_FINE:
787 throw new SecurityException("\"" + providerName + "\" location provider " +
788 "requires ACCESS_FINE_LOCATION permission.");
789 case RESOLUTION_LEVEL_COARSE:
790 throw new SecurityException("\"" + providerName + "\" location provider " +
791 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
792 default:
793 throw new SecurityException("Insufficient permission for \"" + providerName +
794 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700795 }
796 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700797 }
798
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700799 /**
800 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700801 * fused, also including ones that are not permitted to
802 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700803 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700804 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700806 ArrayList<String> out;
807 synchronized (mLock) {
808 out = new ArrayList<String>(mProviders.size());
809 for (LocationProviderInterface provider : mProviders) {
810 String name = provider.getName();
811 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700812 continue;
813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 out.add(name);
815 }
816 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700817
818 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 return out;
820 }
821
Mike Lockwood03ca2162010-04-01 08:10:09 -0700822 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700823 * Return all providers by name, that match criteria and are optionally
824 * enabled.
825 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700826 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700827 @Override
828 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700829 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700830 ArrayList<String> out;
Victoria Lease269518e2012-10-29 08:25:39 -0700831 int callingUserId = UserHandle.getCallingUserId();
832 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700833 try {
834 synchronized (mLock) {
835 out = new ArrayList<String>(mProviders.size());
836 for (LocationProviderInterface provider : mProviders) {
837 String name = provider.getName();
838 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700839 continue;
840 }
Victoria Lease37425c32012-10-16 16:08:48 -0700841 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease269518e2012-10-29 08:25:39 -0700842 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700843 continue;
844 }
845 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
846 name, provider.getProperties(), criteria)) {
847 continue;
848 }
849 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700850 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700851 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700852 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700853 } finally {
854 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700855 }
856
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700857 if (D) Log.d(TAG, "getProviders()=" + out);
858 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700859 }
860
861 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700862 * Return the name of the best provider given a Criteria object.
863 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700864 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700865 * has been deprecated as well. So this method now uses
866 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700867 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700868 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700869 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700870 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700871
872 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700873 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700874 result = pickBest(providers);
875 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
876 return result;
877 }
878 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700879 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700880 result = pickBest(providers);
881 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
882 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700883 }
884
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700885 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700886 return null;
887 }
888
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700889 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700890 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700891 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700892 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
893 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700894 } else {
895 return providers.get(0);
896 }
897 }
898
Nick Pellye0fd6932012-07-11 10:26:13 -0700899 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700900 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
901 LocationProviderInterface p = mProvidersByName.get(provider);
902 if (p == null) {
903 throw new IllegalArgumentException("provider=" + provider);
904 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700905
906 boolean result = LocationProvider.propertiesMeetCriteria(
907 p.getName(), p.getProperties(), criteria);
908 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
909 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700910 }
911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700913 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400914 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500915 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 boolean isEnabled = p.isEnabled();
917 String name = p.getName();
Victoria Lease269518e2012-10-29 08:25:39 -0700918 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700920 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700921 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700923 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700924 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700926 }
927 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700928 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
929 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 }
931 }
932
Victoria Leaseb711d572012-10-02 13:14:11 -0700933 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 int listeners = 0;
935
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500936 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700937 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938
939 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
942 if (records != null) {
943 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700944 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -0700946 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700947 // Sends a notification message to the receiver
948 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
949 if (deadReceivers == null) {
950 deadReceivers = new ArrayList<Receiver>();
951 }
952 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700954 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 }
957 }
958
959 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700960 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 removeUpdatesLocked(deadReceivers.get(i));
962 }
963 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 if (enabled) {
966 p.enable();
967 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700968 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 }
970 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 }
974
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700975 private void applyRequirementsLocked(String provider) {
976 LocationProviderInterface p = mProvidersByName.get(provider);
977 if (p == null) return;
978
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700980 WorkSource worksource = new WorkSource();
981 ProviderRequest providerRequest = new ProviderRequest();
982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700984 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -0700985 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700986 LocationRequest locationRequest = record.mRequest;
987 providerRequest.locationRequests.add(locationRequest);
988 if (locationRequest.getInterval() < providerRequest.interval) {
989 providerRequest.reportLocation = true;
990 providerRequest.interval = locationRequest.getInterval();
991 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700992 }
993 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700994
995 if (providerRequest.reportLocation) {
996 // calculate who to blame for power
997 // This is somewhat arbitrary. We pick a threshold interval
998 // that is slightly higher that the minimum interval, and
999 // spread the blame across all applications with a request
1000 // under that threshold.
1001 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1002 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001003 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001004 LocationRequest locationRequest = record.mRequest;
1005 if (locationRequest.getInterval() <= thresholdInterval) {
1006 worksource.add(record.mReceiver.mUid);
1007 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001008 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001009 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
1011 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001012
1013 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1014 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 }
1016
1017 private class UpdateRecord {
1018 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001019 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001021 Location mLastFixBroadcast;
1022 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023
1024 /**
1025 * Note: must be constructed with lock held.
1026 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001027 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001029 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031
1032 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1033 if (records == null) {
1034 records = new ArrayList<UpdateRecord>();
1035 mRecordsByProvider.put(provider, records);
1036 }
1037 if (!records.contains(this)) {
1038 records.add(this);
1039 }
1040 }
1041
1042 /**
1043 * Method to be called when a record will no longer be used. Calling this multiple times
1044 * must have the same effect as calling it once.
1045 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001046 void disposeLocked(boolean removeReceiver) {
1047 // remove from mRecordsByProvider
1048 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1049 if (globalRecords != null) {
1050 globalRecords.remove(this);
1051 }
1052
1053 if (!removeReceiver) return; // the caller will handle the rest
1054
1055 // remove from Receiver#mUpdateRecords
1056 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1057 if (receiverRecords != null) {
1058 receiverRecords.remove(this.mProvider);
1059
1060 // and also remove the Receiver if it has no more update records
1061 if (removeReceiver && receiverRecords.size() == 0) {
1062 removeUpdatesLocked(mReceiver);
1063 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001064 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 }
1066
1067 @Override
1068 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001069 StringBuilder s = new StringBuilder();
1070 s.append("UpdateRecord[");
1071 s.append(mProvider);
1072 s.append(' ').append(mReceiver.mPackageName).append('(');
1073 s.append(mReceiver.mUid).append(')');
1074 s.append(' ').append(mRequest);
1075 s.append(']');
1076 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 }
1079
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001080 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001081 IBinder binder = listener.asBinder();
1082 Receiver receiver = mReceivers.get(binder);
1083 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001084 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001085 mReceivers.put(binder, receiver);
1086
1087 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001088 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001089 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001090 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001091 return null;
1092 }
1093 }
1094 return receiver;
1095 }
1096
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001097 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001098 Receiver receiver = mReceivers.get(intent);
1099 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001100 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001101 mReceivers.put(intent, receiver);
1102 }
1103 return receiver;
1104 }
1105
Victoria Lease37425c32012-10-16 16:08:48 -07001106 /**
1107 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1108 * and consistency requirements.
1109 *
1110 * @param request the LocationRequest from which to create a sanitized version
1111 * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
1112 * constraints
1113 * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
1114 * @return a version of request that meets the given resolution and consistency requirements
1115 * @hide
1116 */
1117 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1118 LocationRequest sanitizedRequest = new LocationRequest(request);
1119 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1120 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001121 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001122 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001123 break;
1124 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001125 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001126 break;
1127 }
1128 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001129 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1130 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001131 }
Victoria Lease37425c32012-10-16 16:08:48 -07001132 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1133 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001134 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001135 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001136 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001137 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001138 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001139 }
Victoria Lease37425c32012-10-16 16:08:48 -07001140 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001141 }
1142
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001143 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001144 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001145 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001146 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001147 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001148 String[] packages = mPackageManager.getPackagesForUid(uid);
1149 if (packages == null) {
1150 throw new SecurityException("invalid UID " + uid);
1151 }
1152 for (String pkg : packages) {
1153 if (packageName.equals(pkg)) return;
1154 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001155 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001156 }
1157
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001158 private void checkPendingIntent(PendingIntent intent) {
1159 if (intent == null) {
1160 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001161 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001162 }
1163
1164 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1165 int pid, int uid, String packageName) {
1166 if (intent == null && listener == null) {
1167 throw new IllegalArgumentException("need eiter listener or intent");
1168 } else if (intent != null && listener != null) {
1169 throw new IllegalArgumentException("cannot register both listener and intent");
1170 } else if (intent != null) {
1171 checkPendingIntent(intent);
1172 return getReceiver(intent, pid, uid, packageName);
1173 } else {
1174 return getReceiver(listener, pid, uid, packageName);
1175 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001176 }
1177
Nick Pellye0fd6932012-07-11 10:26:13 -07001178 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001179 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1180 PendingIntent intent, String packageName) {
1181 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1182 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001183 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1184 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1185 request.getProvider());
1186 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001188 final int pid = Binder.getCallingPid();
1189 final int uid = Binder.getCallingUid();
1190 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001192 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 long identity = Binder.clearCallingIdentity();
1194 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001195 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001196 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 } finally {
1199 Binder.restoreCallingIdentity(identity);
1200 }
1201 }
1202
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001203 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1204 int pid, int uid, String packageName) {
1205 // Figure out the provider. Either its explicitly request (legacy use cases), or
1206 // use the fused provider
1207 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1208 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001209 if (name == null) {
1210 throw new IllegalArgumentException("provider name must not be null");
1211 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001212 LocationProviderInterface provider = mProvidersByName.get(name);
1213 if (provider == null) {
1214 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1215 }
1216
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001217 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1218 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001219
1220 UpdateRecord record = new UpdateRecord(name, request, receiver);
1221 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1222 if (oldRecord != null) {
1223 oldRecord.disposeLocked(false);
1224 }
1225
Victoria Lease269518e2012-10-29 08:25:39 -07001226 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001227 if (isProviderEnabled) {
1228 applyRequirementsLocked(name);
1229 } else {
1230 // Notify the listener that updates are currently disabled
1231 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 }
1233 }
1234
Nick Pellye0fd6932012-07-11 10:26:13 -07001235 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1237 String packageName) {
1238 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001239
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001240 final int pid = Binder.getCallingPid();
1241 final int uid = Binder.getCallingUid();
1242 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1243
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001244 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001245 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001247 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001248 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001250 } finally {
1251 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 }
1253 }
1254
1255 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001256 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001257
1258 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1259 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1260 synchronized (receiver) {
1261 if (receiver.mPendingBroadcasts > 0) {
1262 decrementPendingBroadcasts();
1263 receiver.mPendingBroadcasts = 0;
1264 }
1265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 }
1267
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001268 // Record which providers were associated with this listener
1269 HashSet<String> providers = new HashSet<String>();
1270 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1271 if (oldRecords != null) {
1272 // Call dispose() on the obsolete update records.
1273 for (UpdateRecord record : oldRecords.values()) {
1274 record.disposeLocked(false);
1275 }
1276 // Accumulate providers
1277 providers.addAll(oldRecords.keySet());
1278 }
1279
1280 // update provider
1281 for (String provider : providers) {
1282 // If provider is already disabled, don't need to do anything
Victoria Lease269518e2012-10-29 08:25:39 -07001283 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 }
1286
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001287 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 }
1289 }
1290
Nick Pellye0fd6932012-07-11 10:26:13 -07001291 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001292 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001293 if (D) Log.d(TAG, "getLastLocation: " + request);
1294 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001295 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001296 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001297 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1298 request.getProvider());
1299 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001300
Victoria Lease269518e2012-10-29 08:25:39 -07001301 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001302 try {
1303 if (mBlacklist.isBlacklisted(packageName)) {
1304 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1305 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001306 return null;
1307 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001308
1309 synchronized (mLock) {
1310 // Figure out the provider. Either its explicitly request (deprecated API's),
1311 // or use the fused provider
1312 String name = request.getProvider();
1313 if (name == null) name = LocationManager.FUSED_PROVIDER;
1314 LocationProviderInterface provider = mProvidersByName.get(name);
1315 if (provider == null) return null;
1316
Victoria Lease269518e2012-10-29 08:25:39 -07001317 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001318
1319 Location location = mLastLocation.get(name);
1320 if (location == null) {
1321 return null;
1322 }
Victoria Lease37425c32012-10-16 16:08:48 -07001323 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001324 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1325 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001326 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001327 }
Victoria Lease37425c32012-10-16 16:08:48 -07001328 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001329 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001330 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001331 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001332 return null;
1333 } finally {
1334 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001335 }
1336 }
1337
1338 @Override
1339 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1340 String packageName) {
1341 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001342 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1343 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001344 checkPendingIntent(intent);
1345 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001346 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1347 request.getProvider());
1348 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001349
Victoria Lease37425c32012-10-16 16:08:48 -07001350 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001351
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001352 // geo-fence manager uses the public location API, need to clear identity
1353 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001354 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1355 // temporary measure until geofences work for secondary users
1356 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1357 return;
1358 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001359 long identity = Binder.clearCallingIdentity();
1360 try {
Victoria Lease37425c32012-10-16 16:08:48 -07001361 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001362 } finally {
1363 Binder.restoreCallingIdentity(identity);
1364 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001365 }
1366
1367 @Override
1368 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001369 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001370 checkPendingIntent(intent);
1371 checkPackageName(packageName);
1372
1373 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1374
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001375 // geo-fence manager uses the public location API, need to clear identity
1376 long identity = Binder.clearCallingIdentity();
1377 try {
1378 mGeofenceManager.removeFence(geofence, intent);
1379 } finally {
1380 Binder.restoreCallingIdentity(identity);
1381 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001382 }
1383
1384
1385 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001387 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 return false;
1389 }
Victoria Lease37425c32012-10-16 16:08:48 -07001390 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1391 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392
1393 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001394 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001396 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 return false;
1398 }
1399 return true;
1400 }
1401
Nick Pellye0fd6932012-07-11 10:26:13 -07001402 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001404 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001405 try {
1406 mGpsStatusProvider.removeGpsStatusListener(listener);
1407 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001408 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410 }
1411 }
1412
Nick Pellye0fd6932012-07-11 10:26:13 -07001413 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001415 if (provider == null) {
1416 // throw NullPointerException to remain compatible with previous implementation
1417 throw new NullPointerException();
1418 }
Victoria Lease37425c32012-10-16 16:08:48 -07001419 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1420 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001423 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 != PackageManager.PERMISSION_GRANTED)) {
1425 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1426 }
1427
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001428 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001429 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001430 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001431
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001432 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 }
1434 }
1435
Nick Pellye0fd6932012-07-11 10:26:13 -07001436 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001437 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001438 if (Binder.getCallingUid() != Process.myUid()) {
1439 throw new SecurityException(
1440 "calling sendNiResponse from outside of the system is not allowed");
1441 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001442 try {
1443 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001444 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001445 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001446 return false;
1447 }
1448 }
1449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001451 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001452 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 * accessed by the caller
1454 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001455 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001456 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001457 if (mProvidersByName.get(provider) == null) {
1458 return null;
1459 }
1460
Victoria Lease37425c32012-10-16 16:08:48 -07001461 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1462 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001464 LocationProviderInterface p;
1465 synchronized (mLock) {
1466 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 }
1468
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001469 if (p == null) return null;
1470 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001471 }
1472
Nick Pellye0fd6932012-07-11 10:26:13 -07001473 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001475 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1476 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001477 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1478
Victoria Lease269518e2012-10-29 08:25:39 -07001479 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001480 try {
1481 synchronized (mLock) {
1482 LocationProviderInterface p = mProvidersByName.get(provider);
1483 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001484
Victoria Lease269518e2012-10-29 08:25:39 -07001485 return isAllowedBySettingsLocked(provider, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -07001486 }
1487 } finally {
1488 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001489 }
1490 }
1491
1492 private void checkCallerIsProvider() {
1493 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1494 == PackageManager.PERMISSION_GRANTED) {
1495 return;
1496 }
1497
1498 // Previously we only used the INSTALL_LOCATION_PROVIDER
1499 // check. But that is system or signature
1500 // protection level which is not flexible enough for
1501 // providers installed oustide the system image. So
1502 // also allow providers with a UID matching the
1503 // currently bound package name
1504
1505 int uid = Binder.getCallingUid();
1506
1507 if (mGeocodeProvider != null) {
1508 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1509 }
1510 for (LocationProviderProxy proxy : mProxyProviders) {
1511 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1512 }
1513 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1514 "or UID of a currently bound location provider");
1515 }
1516
1517 private boolean doesPackageHaveUid(int uid, String packageName) {
1518 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 return false;
1520 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001521 try {
1522 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1523 if (appInfo.uid != uid) {
1524 return false;
1525 }
1526 } catch (NameNotFoundException e) {
1527 return false;
1528 }
1529 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 }
1531
Nick Pellye0fd6932012-07-11 10:26:13 -07001532 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001533 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001534 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001535
Nick Pelly2eeeec22012-07-18 13:13:37 -07001536 if (!location.isComplete()) {
1537 Log.w(TAG, "Dropping incomplete location: " + location);
1538 return;
1539 }
1540
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001541 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1542 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001543 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001544 mLocationHandler.sendMessageAtFrontOfQueue(m);
1545 }
1546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547
Laurent Tu75defb62012-11-01 16:21:52 -07001548 private static boolean shouldBroadcastSafe(
1549 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 // Always broadcast the first update
1551 if (lastLoc == null) {
1552 return true;
1553 }
1554
Nick Pellyf1be6862012-05-15 10:53:42 -07001555 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001556 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001557 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001558 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 return false;
1560 }
1561
1562 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001563 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 if (minDistance > 0.0) {
1565 if (loc.distanceTo(lastLoc) <= minDistance) {
1566 return false;
1567 }
1568 }
1569
Laurent Tu75defb62012-11-01 16:21:52 -07001570 // Check whether sufficient number of udpates is left
1571 if (record.mRequest.getNumUpdates() <= 0) {
1572 return false;
1573 }
1574
1575 // Check whether the expiry date has passed
1576 if (record.mRequest.getExpireAt() < now) {
1577 return false;
1578 }
1579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 return true;
1581 }
1582
Mike Lockwooda4903f22010-02-17 06:42:23 -05001583 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001584 if (D) Log.d(TAG, "incoming location: " + location);
1585
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001586 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001587 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588
Laurent Tu60ec50a2012-10-04 17:00:10 -07001589 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001590 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001591 if (p == null) return;
1592
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001593 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001594 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1595 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001596 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001597 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001598 lastLocation = new Location(provider);
1599 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001600 } else {
1601 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1602 if (noGPSLocation == null && lastNoGPSLocation != null) {
1603 // New location has no no-GPS location: adopt last no-GPS location. This is set
1604 // directly into location because we do not want to notify COARSE clients.
1605 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1606 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001607 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001608 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609
Laurent Tu60ec50a2012-10-04 17:00:10 -07001610 // Skip if there are no UpdateRecords for this provider.
1611 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1612 if (records == null || records.size() == 0) return;
1613
Victoria Lease09016ab2012-09-16 12:33:15 -07001614 // Fetch coarse location
1615 Location coarseLocation = null;
1616 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1617 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1618 }
1619
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620 // Fetch latest status update time
1621 long newStatusUpdateTime = p.getStatusUpdateTime();
1622
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001623 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 Bundle extras = new Bundle();
1625 int status = p.getStatus(extras);
1626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001628 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001629
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001631 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001633 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001634
Victoria Lease269518e2012-10-29 08:25:39 -07001635 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1636 if (receiverUserId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001637 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001638 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001639 " (current user: " + mCurrentUserId + ", app: " +
1640 receiver.mPackageName + ")");
1641 }
1642 continue;
1643 }
1644
Nick Pelly4035f5a2012-08-17 14:43:49 -07001645 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1646 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1647 receiver.mPackageName);
1648 continue;
1649 }
1650
Victoria Lease09016ab2012-09-16 12:33:15 -07001651 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001652 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1653 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001654 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001655 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001656 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001657 if (notifyLocation != null) {
1658 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001659 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001660 if (lastLoc == null) {
1661 lastLoc = new Location(notifyLocation);
1662 r.mLastFixBroadcast = lastLoc;
1663 } else {
1664 lastLoc.set(notifyLocation);
1665 }
1666 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1667 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1668 receiverDead = true;
1669 }
Laurent Tu75defb62012-11-01 16:21:52 -07001670 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
1672 }
1673
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001674 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001676 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001678 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001680 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001681 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001682 }
1683 }
1684
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001685 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001686 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001687 if (deadUpdateRecords == null) {
1688 deadUpdateRecords = new ArrayList<UpdateRecord>();
1689 }
1690 deadUpdateRecords.add(r);
1691 }
1692 // track dead receivers
1693 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001694 if (deadReceivers == null) {
1695 deadReceivers = new ArrayList<Receiver>();
1696 }
1697 if (!deadReceivers.contains(receiver)) {
1698 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
1700 }
1701 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001702
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001703 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001705 for (Receiver receiver : deadReceivers) {
1706 removeUpdatesLocked(receiver);
1707 }
1708 }
1709 if (deadUpdateRecords != null) {
1710 for (UpdateRecord r : deadUpdateRecords) {
1711 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 }
Victoria Leasee0fa1b32012-12-04 15:04:43 -08001713 applyRequirementsLocked(provider);
1714 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 }
1716
1717 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 @Override
1719 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001720 switch (msg.what) {
1721 case MSG_LOCATION_CHANGED:
1722 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1723 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 }
1725 }
1726 }
1727
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001728 private void handleLocationChanged(Location location, boolean passive) {
1729 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001730
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001731 if (!passive) {
1732 // notify passive provider of the new location
1733 mPassiveProvider.updateLocation(location);
1734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001736 synchronized (mLock) {
Victoria Lease269518e2012-10-29 08:25:39 -07001737 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001738 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742
Mike Lockwoode97ae402010-09-29 15:23:46 -04001743 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1744 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001745 public void onPackageDisappeared(String packageName, int reason) {
1746 // remove all receivers associated with this package name
1747 synchronized (mLock) {
1748 ArrayList<Receiver> deadReceivers = null;
1749
1750 for (Receiver receiver : mReceivers.values()) {
1751 if (receiver.mPackageName.equals(packageName)) {
1752 if (deadReceivers == null) {
1753 deadReceivers = new ArrayList<Receiver>();
1754 }
1755 deadReceivers.add(receiver);
1756 }
1757 }
1758
1759 // perform removal outside of mReceivers loop
1760 if (deadReceivers != null) {
1761 for (Receiver receiver : deadReceivers) {
1762 removeUpdatesLocked(receiver);
1763 }
1764 }
1765 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001766 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001767 };
1768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 // Wake locks
1770
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001771 private void incrementPendingBroadcasts() {
1772 synchronized (mWakeLock) {
1773 if (mPendingBroadcasts++ == 0) {
1774 try {
1775 mWakeLock.acquire();
1776 log("Acquired wakelock");
1777 } catch (Exception e) {
1778 // This is to catch a runtime exception thrown when we try to release an
1779 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001780 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001781 }
1782 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001783 }
1784 }
1785
1786 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001787 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001788 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001789 try {
1790 // Release wake lock
1791 if (mWakeLock.isHeld()) {
1792 mWakeLock.release();
1793 log("Released wakelock");
1794 } else {
1795 log("Can't release wakelock again!");
1796 }
1797 } catch (Exception e) {
1798 // This is to catch a runtime exception thrown when we try to release an
1799 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001800 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001801 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001802 }
1803 }
1804 }
1805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 // Geocoder
1807
Nick Pellye0fd6932012-07-11 10:26:13 -07001808 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001809 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001810 return mGeocodeProvider != null;
1811 }
1812
Nick Pellye0fd6932012-07-11 10:26:13 -07001813 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001815 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001816 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001817 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1818 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001820 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 }
1822
Mike Lockwooda55c3212009-04-15 11:10:11 -04001823
Nick Pellye0fd6932012-07-11 10:26:13 -07001824 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001826 double lowerLeftLatitude, double lowerLeftLongitude,
1827 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001828 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001829
1830 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001831 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1832 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1833 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001835 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 }
1837
1838 // Mock Providers
1839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001840 private void checkMockPermissionsSafe() {
1841 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1842 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1843 if (!allowMocks) {
1844 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1845 }
1846
1847 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1848 PackageManager.PERMISSION_GRANTED) {
1849 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001850 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 }
1852
Nick Pellye0fd6932012-07-11 10:26:13 -07001853 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001854 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001855 checkMockPermissionsSafe();
1856
Mike Lockwooda4903f22010-02-17 06:42:23 -05001857 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1858 throw new IllegalArgumentException("Cannot mock the passive location provider");
1859 }
1860
Mike Lockwood86328a92009-10-23 08:38:25 -04001861 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001862 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001863 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001864 // remove the real provider if we are replacing GPS or network provider
1865 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001866 || LocationManager.NETWORK_PROVIDER.equals(name)
1867 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001868 LocationProviderInterface p = mProvidersByName.get(name);
1869 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001870 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001871 }
1872 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001873 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1875 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001876 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001877 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001878 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 updateProvidersLocked();
1880 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001881 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 }
1883
Nick Pellye0fd6932012-07-11 10:26:13 -07001884 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 public void removeTestProvider(String provider) {
1886 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001887 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001888 MockProvider mockProvider = mMockProviders.get(provider);
1889 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1891 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001892 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001893 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001894 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001895
1896 // reinstate real provider if available
1897 LocationProviderInterface realProvider = mRealProviders.get(provider);
1898 if (realProvider != null) {
1899 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001900 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001901 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001903 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 }
1905 }
1906
Nick Pellye0fd6932012-07-11 10:26:13 -07001907 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 public void setTestProviderLocation(String provider, Location loc) {
1909 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001910 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001911 MockProvider mockProvider = mMockProviders.get(provider);
1912 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1914 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001915 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1916 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001917 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001918 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001919 }
1920 }
1921
Nick Pellye0fd6932012-07-11 10:26:13 -07001922 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 public void clearTestProviderLocation(String provider) {
1924 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001925 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001926 MockProvider mockProvider = mMockProviders.get(provider);
1927 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1929 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001930 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001931 }
1932 }
1933
Nick Pellye0fd6932012-07-11 10:26:13 -07001934 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001935 public void setTestProviderEnabled(String provider, boolean enabled) {
1936 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001937 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001938 MockProvider mockProvider = mMockProviders.get(provider);
1939 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1941 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001942 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001944 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 mEnabledProviders.add(provider);
1946 mDisabledProviders.remove(provider);
1947 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001948 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001949 mEnabledProviders.remove(provider);
1950 mDisabledProviders.add(provider);
1951 }
1952 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001953 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 }
1955 }
1956
Nick Pellye0fd6932012-07-11 10:26:13 -07001957 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958 public void clearTestProviderEnabled(String provider) {
1959 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001960 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001961 MockProvider mockProvider = mMockProviders.get(provider);
1962 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001963 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1964 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001965 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 mEnabledProviders.remove(provider);
1967 mDisabledProviders.remove(provider);
1968 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001969 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 }
1971 }
1972
Nick Pellye0fd6932012-07-11 10:26:13 -07001973 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1975 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001976 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001977 MockProvider mockProvider = mMockProviders.get(provider);
1978 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1980 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001981 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 }
1983 }
1984
Nick Pellye0fd6932012-07-11 10:26:13 -07001985 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 public void clearTestProviderStatus(String provider) {
1987 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001988 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001989 MockProvider mockProvider = mMockProviders.get(provider);
1990 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1992 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001993 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 }
1995 }
1996
1997 private void log(String log) {
1998 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001999 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
2001 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002002
2003 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2005 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2006 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002007 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 + Binder.getCallingPid()
2009 + ", uid=" + Binder.getCallingUid());
2010 return;
2011 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002012
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002013 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002014 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002016 for (Receiver receiver : mReceivers.values()) {
2017 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002020 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2021 pw.println(" " + entry.getKey() + ":");
2022 for (UpdateRecord record : entry.getValue()) {
2023 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 }
2025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002026 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002027 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2028 String provider = entry.getKey();
2029 Location location = entry.getValue();
2030 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002032
Nick Pellye0fd6932012-07-11 10:26:13 -07002033 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002035 if (mEnabledProviders.size() > 0) {
2036 pw.println(" Enabled Providers:");
2037 for (String i : mEnabledProviders) {
2038 pw.println(" " + i);
2039 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002041 }
2042 if (mDisabledProviders.size() > 0) {
2043 pw.println(" Disabled Providers:");
2044 for (String i : mDisabledProviders) {
2045 pw.println(" " + i);
2046 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002047 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002048 pw.append(" ");
2049 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002050 if (mMockProviders.size() > 0) {
2051 pw.println(" Mock Providers:");
2052 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002053 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 }
2055 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002056
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002057 pw.append(" fudger: ");
2058 mLocationFudger.dump(fd, pw, args);
2059
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002060 if (args.length > 0 && "short".equals(args[0])) {
2061 return;
2062 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002063 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002064 pw.print(provider.getName() + " Internal State");
2065 if (provider instanceof LocationProviderProxy) {
2066 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2067 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002068 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002069 pw.println(":");
2070 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002071 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002072 }
2073 }
2074}