blob: 946ed7821493c650aaa6e6734c4bc72e04efe03b [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
Dianne Hackborna06de0f2012-12-11 16:34:47 -080019import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070021import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070025import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070026import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050027import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070029import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050030import android.content.pm.ResolveInfo;
31import android.content.pm.Signature;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050032import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070033import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070035import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050036import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070037import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040039import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.location.ILocationListener;
41import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040042import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.location.Location;
44import android.location.LocationManager;
45import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070046import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.Binder;
48import android.os.Bundle;
49import android.os.Handler;
Victoria Lease5cd731a2012-12-19 15:04:21 -080050import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070052import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.Message;
54import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070055import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.RemoteException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080057import android.os.ServiceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070058import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070059import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070060import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080063import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
Dianne Hackborna06de0f2012-12-11 16:34:47 -080065import com.android.internal.app.IAppOpsService;
Mike Lockwoode97ae402010-09-29 15:23:46 -040066import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070067import com.android.internal.location.ProviderProperties;
68import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040069import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070070import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040071import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070072import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070073import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040074import com.android.server.location.LocationProviderInterface;
75import com.android.server.location.LocationProviderProxy;
76import com.android.server.location.MockProvider;
77import com.android.server.location.PassiveProvider;
78
79import java.io.FileDescriptor;
80import java.io.PrintWriter;
81import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070082import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040083import java.util.HashMap;
84import java.util.HashSet;
85import java.util.List;
86import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040087import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
89/**
90 * The service class that manages LocationProviders and issues location
91 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 */
Victoria Lease5cd731a2012-12-19 15:04:21 -080093public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070095 public static final boolean D = false;
96
97 private static final String WAKELOCK_KEY = TAG;
98 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099
Victoria Lease37425c32012-10-16 16:08:48 -0700100 // Location resolution level: no location data whatsoever
101 private static final int RESOLUTION_LEVEL_NONE = 0;
102 // Location resolution level: coarse location data only
103 private static final int RESOLUTION_LEVEL_COARSE = 1;
104 // Location resolution level: fine location data
105 private static final int RESOLUTION_LEVEL_FINE = 2;
106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700108 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700110 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400111 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700112 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
113
114 private static final String NETWORK_LOCATION_SERVICE_ACTION =
115 "com.android.location.service.v2.NetworkLocationProvider";
116 private static final String FUSED_LOCATION_SERVICE_ACTION =
117 "com.android.location.service.FusedLocationProvider";
118
119 private static final int MSG_LOCATION_CHANGED = 1;
120
Nick Pellyf1be6862012-05-15 10:53:42 -0700121 // Location Providers may sometimes deliver location updates
122 // slightly faster that requested - provide grace period so
123 // we don't unnecessarily filter events that are otherwise on
124 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700125 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700126
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700127 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
128
129 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800130 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700131
132 // used internally for synchronization
133 private final Object mLock = new Object();
134
Victoria Lease5cd731a2012-12-19 15:04:21 -0800135 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700136 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700137 private GeofenceManager mGeofenceManager;
138 private PowerManager.WakeLock mWakeLock;
139 private PackageManager mPackageManager;
140 private GeocoderProxy mGeocodeProvider;
141 private IGpsStatusProvider mGpsStatusProvider;
142 private INetInitiatedListener mNetInitiatedListener;
143 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700144 private PassiveProvider mPassiveProvider; // track passive provider for special cases
145 private LocationBlacklist mBlacklist;
Victoria Lease5cd731a2012-12-19 15:04:21 -0800146 private HandlerThread mHandlerThread;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700147
148 // --- fields below are protected by mWakeLock ---
149 private int mPendingBroadcasts;
150
151 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 // Set of providers that are explicitly enabled
153 private final Set<String> mEnabledProviders = new HashSet<String>();
154
155 // Set of providers that are explicitly disabled
156 private final Set<String> mDisabledProviders = new HashSet<String>();
157
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700158 // Mock (test) providers
159 private final HashMap<String, MockProvider> mMockProviders =
160 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400163 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700165 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500166 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // real providers, saved here when mocked out
170 private final HashMap<String, LocationProviderInterface> mRealProviders =
171 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700173 // mapping from provider name to provider
174 private final HashMap<String, LocationProviderInterface> mProvidersByName =
175 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 // mapping from provider name to all its UpdateRecords
178 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
179 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700180
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 // mapping from provider name to last known location
182 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700184 // all providers that operate over proxy, for authorizing incoming location
185 private final ArrayList<LocationProviderProxy> mProxyProviders =
186 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187
Victoria Lease38389b62012-09-30 11:44:22 -0700188 // current active user on the device - other users are denied location data
189 private int mCurrentUserId = UserHandle.USER_OWNER;
190
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700191 public LocationManagerService(Context context) {
192 super();
193 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800194 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 if (D) Log.d(TAG, "Constructed");
197
198 // most startup is deferred until systemReady()
199 }
200
201 public void systemReady() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700202 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800203 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700204
Victoria Lease5cd731a2012-12-19 15:04:21 -0800205 // fetch package manager
206 mPackageManager = mContext.getPackageManager();
207
208 // prepare wake lock
209 PowerManager powerManager =
210 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
211 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
212
213 // prepare worker thread
214 mHandlerThread = new HandlerThread(THREAD_NAME, Process.THREAD_PRIORITY_BACKGROUND);
215 mHandlerThread.start();
216 mLocationHandler = new LocationWorkerHandler(mHandlerThread.getLooper());
217
218 // prepare mLocationHandler's dependents
219 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
220 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
221 mBlacklist.init();
222 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
223
224 // prepare providers
225 loadProvidersLocked();
226 updateProvidersLocked();
227 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700228
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700229 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700230 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700231 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700232 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800233 @Override
234 public void onChange(boolean selfChange) {
235 synchronized (mLock) {
236 updateProvidersLocked();
237 }
238 }
239 }, UserHandle.USER_ALL);
240 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700241
Victoria Lease38389b62012-09-30 11:44:22 -0700242 // listen for user change
243 IntentFilter intentFilter = new IntentFilter();
244 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
245
246 mContext.registerReceiverAsUser(new BroadcastReceiver() {
247 @Override
248 public void onReceive(Context context, Intent intent) {
249 String action = intent.getAction();
250 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
251 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
252 }
253 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800254 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700255 }
256
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500257 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
258 PackageManager pm = mContext.getPackageManager();
259 String systemPackageName = mContext.getPackageName();
260 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
261
262 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
263 new Intent(FUSED_LOCATION_SERVICE_ACTION),
264 PackageManager.GET_META_DATA, mCurrentUserId);
265 for (ResolveInfo rInfo : rInfos) {
266 String packageName = rInfo.serviceInfo.packageName;
267
268 // Check that the signature is in the list of supported sigs. If it's not in
269 // this list the standard provider binding logic won't bind to it.
270 try {
271 PackageInfo pInfo;
272 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
273 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
274 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
275 ", but has wrong signature, ignoring");
276 continue;
277 }
278 } catch (NameNotFoundException e) {
279 Log.e(TAG, "missing package: " + packageName);
280 continue;
281 }
282
283 // Get the version info
284 if (rInfo.serviceInfo.metaData == null) {
285 Log.w(TAG, "Found fused provider without metadata: " + packageName);
286 continue;
287 }
288
289 int version = rInfo.serviceInfo.metaData.getInt(
290 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
291 if (version == 0) {
292 // This should be the fallback fused location provider.
293
294 // Make sure it's in the system partition.
295 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
296 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
297 continue;
298 }
299
300 // Check that the fallback is signed the same as the OS
301 // as a proxy for coreApp="true"
302 if (pm.checkSignatures(systemPackageName, packageName)
303 != PackageManager.SIGNATURE_MATCH) {
304 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
305 + packageName);
306 continue;
307 }
308
309 // Found a valid fallback.
310 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
311 return;
312 } else {
313 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
314 }
315 }
316
317 throw new IllegalStateException("Unable to find a fused location provider that is in the "
318 + "system partition with version 0 and signed with the platform certificate. "
319 + "Such a package is needed to provide a default fused location provider in the "
320 + "event that no other fused location provider has been installed or is currently "
321 + "available. For example, coreOnly boot mode when decrypting the data "
322 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
323 }
324
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700325 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700326 // create a passive location provider, which is always enabled
327 PassiveProvider passiveProvider = new PassiveProvider(this);
328 addProviderLocked(passiveProvider);
329 mEnabledProviders.add(passiveProvider.getName());
330 mPassiveProvider = passiveProvider;
331
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700332 if (GpsLocationProvider.isSupported()) {
333 // Create a gps location provider
Victoria Lease5cd731a2012-12-19 15:04:21 -0800334 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
335 mLocationHandler.getLooper());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700336 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
337 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
338 addProviderLocked(gpsProvider);
339 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
340 }
341
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700342 /*
343 Load package name(s) containing location provider support.
344 These packages can contain services implementing location providers:
345 Geocoder Provider, Network Location Provider, and
346 Fused Location Provider. They will each be searched for
347 service components implementing these providers.
348 The location framework also has support for installation
349 of new location providers at run-time. The new package does not
350 have to be explicitly listed here, however it must have a signature
351 that matches the signature of at least one package on this list.
352 */
353 Resources resources = mContext.getResources();
354 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500355 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700356 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500357 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
358 Arrays.toString(pkgs));
359 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
360
361 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700362
363 // bind to network provider
364 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
365 mContext,
366 LocationManager.NETWORK_PROVIDER,
367 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700368 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700369 if (networkProvider != null) {
370 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
371 mProxyProviders.add(networkProvider);
372 addProviderLocked(networkProvider);
373 } else {
374 Slog.w(TAG, "no network location provider found");
375 }
376
377 // bind to fused provider
378 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
379 mContext,
380 LocationManager.FUSED_PROVIDER,
381 FUSED_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700382 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700383 if (fusedLocationProvider != null) {
384 addProviderLocked(fusedLocationProvider);
385 mProxyProviders.add(fusedLocationProvider);
386 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700387 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700388 } else {
389 Slog.e(TAG, "no fused location provider found",
390 new IllegalStateException("Location service needs a fused location provider"));
391 }
392
393 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700394 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
Victoria Lease5cd731a2012-12-19 15:04:21 -0800395 mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700396 if (mGeocodeProvider == null) {
397 Slog.e(TAG, "no geocoder provider found");
398 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700399 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700402 * Called when the device's active user changes.
403 * @param userId the new active user's UserId
404 */
405 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700406 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700407 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700408 mLastLocation.clear();
409 for (LocationProviderInterface p : mProviders) {
410 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Lease269518e2012-10-29 08:25:39 -0700411 p.switchUser(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700412 }
Victoria Lease38389b62012-09-30 11:44:22 -0700413 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700414 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700415 }
416 }
417
418 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
420 * location updates.
421 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700422 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700423 final int mUid; // uid of receiver
424 final int mPid; // pid of receiver
425 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700426 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 final ILocationListener mListener;
429 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700431
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400432 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700433
Mike Lockwood48f17512009-04-23 09:12:08 -0700434 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700436 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
437 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700440 if (listener != null) {
441 mKey = listener.asBinder();
442 } else {
443 mKey = intent;
444 }
Victoria Lease37425c32012-10-16 16:08:48 -0700445 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700446 mUid = uid;
447 mPid = pid;
448 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 }
450
451 @Override
452 public boolean equals(Object otherObj) {
453 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700454 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 }
456 return false;
457 }
458
459 @Override
460 public int hashCode() {
461 return mKey.hashCode();
462 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 @Override
465 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700466 StringBuilder s = new StringBuilder();
467 s.append("Reciever[");
468 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700470 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700472 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700474 for (String p : mUpdateRecords.keySet()) {
475 s.append(" ").append(mUpdateRecords.get(p).toString());
476 }
477 s.append("]");
478 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 }
480
481 public boolean isListener() {
482 return mListener != null;
483 }
484
485 public boolean isPendingIntent() {
486 return mPendingIntent != null;
487 }
488
489 public ILocationListener getListener() {
490 if (mListener != null) {
491 return mListener;
492 }
493 throw new IllegalStateException("Request for non-existent listener");
494 }
495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
497 if (mListener != null) {
498 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700499 synchronized (this) {
500 // synchronize to ensure incrementPendingBroadcastsLocked()
501 // is called before decrementPendingBroadcasts()
502 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700503 // call this after broadcasting so we do not increment
504 // if we throw an exeption.
505 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 } catch (RemoteException e) {
508 return false;
509 }
510 } else {
511 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800512 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
514 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700515 synchronized (this) {
516 // synchronize to ensure incrementPendingBroadcastsLocked()
517 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700518 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700519 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700520 // call this after broadcasting so we do not increment
521 // if we throw an exeption.
522 incrementPendingBroadcastsLocked();
523 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 } catch (PendingIntent.CanceledException e) {
525 return false;
526 }
527 }
528 return true;
529 }
530
531 public boolean callLocationChangedLocked(Location location) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800532 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_LOCATION, mUid, mPackageName)
533 != AppOpsManager.MODE_ALLOWED) {
534 return true;
535 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 if (mListener != null) {
537 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700538 synchronized (this) {
539 // synchronize to ensure incrementPendingBroadcastsLocked()
540 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800541 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700542 // call this after broadcasting so we do not increment
543 // if we throw an exeption.
544 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 } catch (RemoteException e) {
547 return false;
548 }
549 } else {
550 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800551 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700553 synchronized (this) {
554 // synchronize to ensure incrementPendingBroadcastsLocked()
555 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700556 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700557 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700558 // call this after broadcasting so we do not increment
559 // if we throw an exeption.
560 incrementPendingBroadcastsLocked();
561 }
562 } catch (PendingIntent.CanceledException e) {
563 return false;
564 }
565 }
566 return true;
567 }
568
569 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
570 if (mListener != null) {
571 try {
572 synchronized (this) {
573 // synchronize to ensure incrementPendingBroadcastsLocked()
574 // is called before decrementPendingBroadcasts()
575 if (enabled) {
576 mListener.onProviderEnabled(provider);
577 } else {
578 mListener.onProviderDisabled(provider);
579 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700580 // call this after broadcasting so we do not increment
581 // if we throw an exeption.
582 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700583 }
584 } catch (RemoteException e) {
585 return false;
586 }
587 } else {
588 Intent providerIntent = new Intent();
589 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
590 try {
591 synchronized (this) {
592 // synchronize to ensure incrementPendingBroadcastsLocked()
593 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700594 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700595 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700596 // call this after broadcasting so we do not increment
597 // if we throw an exeption.
598 incrementPendingBroadcastsLocked();
599 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 } catch (PendingIntent.CanceledException e) {
601 return false;
602 }
603 }
604 return true;
605 }
606
Nick Pellyf1be6862012-05-15 10:53:42 -0700607 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700609 if (D) Log.d(TAG, "Location listener died");
610
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400611 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 removeUpdatesLocked(this);
613 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700614 synchronized (this) {
615 if (mPendingBroadcasts > 0) {
616 LocationManagerService.this.decrementPendingBroadcasts();
617 mPendingBroadcasts = 0;
618 }
619 }
620 }
621
Nick Pellye0fd6932012-07-11 10:26:13 -0700622 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700623 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
624 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400625 synchronized (this) {
626 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700627 }
628 }
629
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400630 // this must be called while synchronized by caller in a synchronized block
631 // containing the sending of the broadcaset
632 private void incrementPendingBroadcastsLocked() {
633 if (mPendingBroadcasts++ == 0) {
634 LocationManagerService.this.incrementPendingBroadcasts();
635 }
636 }
637
638 private void decrementPendingBroadcastsLocked() {
639 if (--mPendingBroadcasts == 0) {
640 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700641 }
642 }
643 }
644
Nick Pellye0fd6932012-07-11 10:26:13 -0700645 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700646 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400647 //Do not use getReceiver here as that will add the ILocationListener to
648 //the receiver list if it is not found. If it is not found then the
649 //LocationListener was removed when it had a pending broadcast and should
650 //not be added back.
651 IBinder binder = listener.asBinder();
652 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700653 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400654 synchronized (receiver) {
655 // so wakelock calls will succeed
656 long identity = Binder.clearCallingIdentity();
657 receiver.decrementPendingBroadcastsLocked();
658 Binder.restoreCallingIdentity(identity);
659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 }
661 }
662
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700663 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400664 mProviders.add(provider);
665 mProvidersByName.put(provider.getName(), provider);
666 }
667
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700668 private void removeProviderLocked(LocationProviderInterface provider) {
669 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400670 mProviders.remove(provider);
671 mProvidersByName.remove(provider.getName());
672 }
673
Mike Lockwood3d12b512009-04-21 23:25:35 -0700674
Victoria Lease269518e2012-10-29 08:25:39 -0700675 private boolean isAllowedBySettingsLocked(String provider, int userId) {
676 if (userId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700677 return false;
678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 if (mEnabledProviders.contains(provider)) {
680 return true;
681 }
682 if (mDisabledProviders.contains(provider)) {
683 return false;
684 }
685 // Use system settings
686 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687
Victoria Leaseb711d572012-10-02 13:14:11 -0700688 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 }
690
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700691 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700692 * Returns the permission string associated with the specified resolution level.
693 *
694 * @param resolutionLevel the resolution level
695 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700696 */
Victoria Lease37425c32012-10-16 16:08:48 -0700697 private String getResolutionPermission(int resolutionLevel) {
698 switch (resolutionLevel) {
699 case RESOLUTION_LEVEL_FINE:
700 return android.Manifest.permission.ACCESS_FINE_LOCATION;
701 case RESOLUTION_LEVEL_COARSE:
702 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
703 default:
704 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700706 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700707
Victoria Leaseda479c52012-10-15 15:24:16 -0700708 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700709 * Returns the resolution level allowed to the given PID/UID pair.
710 *
711 * @param pid the PID
712 * @param uid the UID
713 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700714 */
Victoria Lease37425c32012-10-16 16:08:48 -0700715 private int getAllowedResolutionLevel(int pid, int uid) {
716 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
717 pid, uid) == PackageManager.PERMISSION_GRANTED) {
718 return RESOLUTION_LEVEL_FINE;
719 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
720 pid, uid) == PackageManager.PERMISSION_GRANTED) {
721 return RESOLUTION_LEVEL_COARSE;
722 } else {
723 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700724 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700725 }
726
727 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700728 * Returns the resolution level allowed to the caller
729 *
730 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700731 */
Victoria Lease37425c32012-10-16 16:08:48 -0700732 private int getCallerAllowedResolutionLevel() {
733 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
734 }
735
736 /**
737 * Throw SecurityException if specified resolution level is insufficient to use geofences.
738 *
739 * @param allowedResolutionLevel resolution level allowed to caller
740 */
741 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
742 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700743 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
744 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 }
746
Victoria Lease37425c32012-10-16 16:08:48 -0700747 /**
748 * Return the minimum resolution level required to use the specified location provider.
749 *
750 * @param provider the name of the location provider
751 * @return minimum resolution level required for provider
752 */
753 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700754 if (LocationManager.GPS_PROVIDER.equals(provider) ||
755 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
756 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700757 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700758 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
759 LocationManager.FUSED_PROVIDER.equals(provider)) {
760 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700761 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700762 } else {
763 // mock providers
764 LocationProviderInterface lp = mMockProviders.get(provider);
765 if (lp != null) {
766 ProviderProperties properties = lp.getProperties();
767 if (properties != null) {
768 if (properties.mRequiresSatellite) {
769 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700770 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700771 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
772 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700773 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700774 }
775 }
776 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700777 }
Victoria Lease37425c32012-10-16 16:08:48 -0700778 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700779 }
780
Victoria Lease37425c32012-10-16 16:08:48 -0700781 /**
782 * Throw SecurityException if specified resolution level is insufficient to use the named
783 * location provider.
784 *
785 * @param allowedResolutionLevel resolution level allowed to caller
786 * @param providerName the name of the location provider
787 */
788 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
789 String providerName) {
790 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
791 if (allowedResolutionLevel < requiredResolutionLevel) {
792 switch (requiredResolutionLevel) {
793 case RESOLUTION_LEVEL_FINE:
794 throw new SecurityException("\"" + providerName + "\" location provider " +
795 "requires ACCESS_FINE_LOCATION permission.");
796 case RESOLUTION_LEVEL_COARSE:
797 throw new SecurityException("\"" + providerName + "\" location provider " +
798 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
799 default:
800 throw new SecurityException("Insufficient permission for \"" + providerName +
801 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700802 }
803 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700804 }
805
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700806 /**
807 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700808 * fused, also including ones that are not permitted to
809 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700810 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700811 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700813 ArrayList<String> out;
814 synchronized (mLock) {
815 out = new ArrayList<String>(mProviders.size());
816 for (LocationProviderInterface provider : mProviders) {
817 String name = provider.getName();
818 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700819 continue;
820 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 out.add(name);
822 }
823 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700824
825 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 return out;
827 }
828
Mike Lockwood03ca2162010-04-01 08:10:09 -0700829 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700830 * Return all providers by name, that match criteria and are optionally
831 * enabled.
832 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700833 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700834 @Override
835 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700836 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700837 ArrayList<String> out;
Victoria Lease269518e2012-10-29 08:25:39 -0700838 int callingUserId = UserHandle.getCallingUserId();
839 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700840 try {
841 synchronized (mLock) {
842 out = new ArrayList<String>(mProviders.size());
843 for (LocationProviderInterface provider : mProviders) {
844 String name = provider.getName();
845 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700846 continue;
847 }
Victoria Lease37425c32012-10-16 16:08:48 -0700848 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease269518e2012-10-29 08:25:39 -0700849 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700850 continue;
851 }
852 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
853 name, provider.getProperties(), criteria)) {
854 continue;
855 }
856 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700857 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700858 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700859 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700860 } finally {
861 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700862 }
863
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700864 if (D) Log.d(TAG, "getProviders()=" + out);
865 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700866 }
867
868 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700869 * Return the name of the best provider given a Criteria object.
870 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700871 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700872 * has been deprecated as well. So this method now uses
873 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700874 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700875 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700876 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700877 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700878
879 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700880 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700881 result = pickBest(providers);
882 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
883 return result;
884 }
885 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700886 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700887 result = pickBest(providers);
888 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
889 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700890 }
891
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700892 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700893 return null;
894 }
895
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700896 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700897 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700898 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700899 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
900 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700901 } else {
902 return providers.get(0);
903 }
904 }
905
Nick Pellye0fd6932012-07-11 10:26:13 -0700906 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700907 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
908 LocationProviderInterface p = mProvidersByName.get(provider);
909 if (p == null) {
910 throw new IllegalArgumentException("provider=" + provider);
911 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700912
913 boolean result = LocationProvider.propertiesMeetCriteria(
914 p.getName(), p.getProperties(), criteria);
915 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
916 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700917 }
918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700920 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400921 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500922 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 boolean isEnabled = p.isEnabled();
924 String name = p.getName();
Victoria Lease269518e2012-10-29 08:25:39 -0700925 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700927 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700928 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700930 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700931 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700933 }
934 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700935 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
936 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 }
938 }
939
Victoria Leaseb711d572012-10-02 13:14:11 -0700940 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 int listeners = 0;
942
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500943 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700944 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945
946 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700947
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
949 if (records != null) {
950 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700951 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -0700953 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700954 // Sends a notification message to the receiver
955 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
956 if (deadReceivers == null) {
957 deadReceivers = new ArrayList<Receiver>();
958 }
959 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700961 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 }
964 }
965
966 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700967 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 removeUpdatesLocked(deadReceivers.get(i));
969 }
970 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700971
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 if (enabled) {
973 p.enable();
974 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700975 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 }
977 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 }
981
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700982 private void applyRequirementsLocked(String provider) {
983 LocationProviderInterface p = mProvidersByName.get(provider);
984 if (p == null) return;
985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700987 WorkSource worksource = new WorkSource();
988 ProviderRequest providerRequest = new ProviderRequest();
989
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700991 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -0700992 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700993 LocationRequest locationRequest = record.mRequest;
994 providerRequest.locationRequests.add(locationRequest);
995 if (locationRequest.getInterval() < providerRequest.interval) {
996 providerRequest.reportLocation = true;
997 providerRequest.interval = locationRequest.getInterval();
998 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700999 }
1000 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001001
1002 if (providerRequest.reportLocation) {
1003 // calculate who to blame for power
1004 // This is somewhat arbitrary. We pick a threshold interval
1005 // that is slightly higher that the minimum interval, and
1006 // spread the blame across all applications with a request
1007 // under that threshold.
1008 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1009 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001010 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001011 LocationRequest locationRequest = record.mRequest;
1012 if (locationRequest.getInterval() <= thresholdInterval) {
Dianne Hackborn002a54e2013-01-10 17:34:55 -08001013 worksource.add(record.mReceiver.mUid, record.mReceiver.mPackageName);
Victoria Leaseb711d572012-10-02 13:14:11 -07001014 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001015 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001016 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 }
1018 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001019
1020 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1021 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 }
1023
1024 private class UpdateRecord {
1025 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001026 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001028 Location mLastFixBroadcast;
1029 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030
1031 /**
1032 * Note: must be constructed with lock held.
1033 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001034 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001036 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038
1039 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1040 if (records == null) {
1041 records = new ArrayList<UpdateRecord>();
1042 mRecordsByProvider.put(provider, records);
1043 }
1044 if (!records.contains(this)) {
1045 records.add(this);
1046 }
1047 }
1048
1049 /**
1050 * Method to be called when a record will no longer be used. Calling this multiple times
1051 * must have the same effect as calling it once.
1052 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001053 void disposeLocked(boolean removeReceiver) {
1054 // remove from mRecordsByProvider
1055 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1056 if (globalRecords != null) {
1057 globalRecords.remove(this);
1058 }
1059
1060 if (!removeReceiver) return; // the caller will handle the rest
1061
1062 // remove from Receiver#mUpdateRecords
1063 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1064 if (receiverRecords != null) {
1065 receiverRecords.remove(this.mProvider);
1066
1067 // and also remove the Receiver if it has no more update records
1068 if (removeReceiver && receiverRecords.size() == 0) {
1069 removeUpdatesLocked(mReceiver);
1070 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001071 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 }
1073
1074 @Override
1075 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001076 StringBuilder s = new StringBuilder();
1077 s.append("UpdateRecord[");
1078 s.append(mProvider);
1079 s.append(' ').append(mReceiver.mPackageName).append('(');
1080 s.append(mReceiver.mUid).append(')');
1081 s.append(' ').append(mRequest);
1082 s.append(']');
1083 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 }
1086
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001087 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001088 IBinder binder = listener.asBinder();
1089 Receiver receiver = mReceivers.get(binder);
1090 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001091 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001092 mReceivers.put(binder, receiver);
1093
1094 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001095 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001096 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001097 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001098 return null;
1099 }
1100 }
1101 return receiver;
1102 }
1103
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001104 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001105 Receiver receiver = mReceivers.get(intent);
1106 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001107 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001108 mReceivers.put(intent, receiver);
1109 }
1110 return receiver;
1111 }
1112
Victoria Lease37425c32012-10-16 16:08:48 -07001113 /**
1114 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1115 * and consistency requirements.
1116 *
1117 * @param request the LocationRequest from which to create a sanitized version
1118 * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
1119 * constraints
1120 * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
1121 * @return a version of request that meets the given resolution and consistency requirements
1122 * @hide
1123 */
1124 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1125 LocationRequest sanitizedRequest = new LocationRequest(request);
1126 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1127 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001128 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001129 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001130 break;
1131 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001132 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001133 break;
1134 }
1135 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001136 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1137 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001138 }
Victoria Lease37425c32012-10-16 16:08:48 -07001139 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1140 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001141 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001142 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001143 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001144 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001145 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001146 }
Victoria Lease37425c32012-10-16 16:08:48 -07001147 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001148 }
1149
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001150 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001151 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001152 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001153 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001154 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001155 String[] packages = mPackageManager.getPackagesForUid(uid);
1156 if (packages == null) {
1157 throw new SecurityException("invalid UID " + uid);
1158 }
1159 for (String pkg : packages) {
1160 if (packageName.equals(pkg)) return;
1161 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001162 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001163 }
1164
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001165 private void checkPendingIntent(PendingIntent intent) {
1166 if (intent == null) {
1167 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001168 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001169 }
1170
1171 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1172 int pid, int uid, String packageName) {
1173 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001174 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001175 } else if (intent != null && listener != null) {
1176 throw new IllegalArgumentException("cannot register both listener and intent");
1177 } else if (intent != null) {
1178 checkPendingIntent(intent);
1179 return getReceiver(intent, pid, uid, packageName);
1180 } else {
1181 return getReceiver(listener, pid, uid, packageName);
1182 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001183 }
1184
Nick Pellye0fd6932012-07-11 10:26:13 -07001185 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001186 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1187 PendingIntent intent, String packageName) {
1188 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1189 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001190 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1191 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1192 request.getProvider());
1193 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001195 final int pid = Binder.getCallingPid();
1196 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001197 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 long identity = Binder.clearCallingIdentity();
1199 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001200 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1201 // a location.
1202 mAppOps.noteOp(AppOpsManager.OP_LOCATION, uid, packageName);
1203 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1204
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001205 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001206 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001207 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 } finally {
1209 Binder.restoreCallingIdentity(identity);
1210 }
1211 }
1212
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001213 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1214 int pid, int uid, String packageName) {
1215 // Figure out the provider. Either its explicitly request (legacy use cases), or
1216 // use the fused provider
1217 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1218 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001219 if (name == null) {
1220 throw new IllegalArgumentException("provider name must not be null");
1221 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 LocationProviderInterface provider = mProvidersByName.get(name);
1223 if (provider == null) {
1224 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1225 }
1226
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001227 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1228 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001229
1230 UpdateRecord record = new UpdateRecord(name, request, receiver);
1231 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1232 if (oldRecord != null) {
1233 oldRecord.disposeLocked(false);
1234 }
1235
Victoria Lease269518e2012-10-29 08:25:39 -07001236 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001237 if (isProviderEnabled) {
1238 applyRequirementsLocked(name);
1239 } else {
1240 // Notify the listener that updates are currently disabled
1241 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 }
1243 }
1244
Nick Pellye0fd6932012-07-11 10:26:13 -07001245 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001246 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1247 String packageName) {
1248 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001249
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001250 final int pid = Binder.getCallingPid();
1251 final int uid = Binder.getCallingUid();
1252 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1253
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001254 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001255 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001257 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001258 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001260 } finally {
1261 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 }
1263 }
1264
1265 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001266 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001267
1268 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1269 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1270 synchronized (receiver) {
1271 if (receiver.mPendingBroadcasts > 0) {
1272 decrementPendingBroadcasts();
1273 receiver.mPendingBroadcasts = 0;
1274 }
1275 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 }
1277
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001278 // Record which providers were associated with this listener
1279 HashSet<String> providers = new HashSet<String>();
1280 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1281 if (oldRecords != null) {
1282 // Call dispose() on the obsolete update records.
1283 for (UpdateRecord record : oldRecords.values()) {
1284 record.disposeLocked(false);
1285 }
1286 // Accumulate providers
1287 providers.addAll(oldRecords.keySet());
1288 }
1289
1290 // update provider
1291 for (String provider : providers) {
1292 // If provider is already disabled, don't need to do anything
Victoria Lease269518e2012-10-29 08:25:39 -07001293 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001294 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 }
1296
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001297 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 }
1299 }
1300
Nick Pellye0fd6932012-07-11 10:26:13 -07001301 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001302 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001303 if (D) Log.d(TAG, "getLastLocation: " + request);
1304 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001305 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001306 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001307 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1308 request.getProvider());
1309 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001310
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001311 final int uid = Binder.getCallingUid();
1312 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001313 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001314 if (mAppOps.noteOp(AppOpsManager.OP_LOCATION, uid, packageName)
1315 != AppOpsManager.MODE_ALLOWED) {
1316 return null;
1317 }
1318
Victoria Leaseb711d572012-10-02 13:14:11 -07001319 if (mBlacklist.isBlacklisted(packageName)) {
1320 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1321 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001322 return null;
1323 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001324
1325 synchronized (mLock) {
1326 // Figure out the provider. Either its explicitly request (deprecated API's),
1327 // or use the fused provider
1328 String name = request.getProvider();
1329 if (name == null) name = LocationManager.FUSED_PROVIDER;
1330 LocationProviderInterface provider = mProvidersByName.get(name);
1331 if (provider == null) return null;
1332
Victoria Lease269518e2012-10-29 08:25:39 -07001333 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001334
1335 Location location = mLastLocation.get(name);
1336 if (location == null) {
1337 return null;
1338 }
Victoria Lease37425c32012-10-16 16:08:48 -07001339 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001340 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1341 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001342 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001343 }
Victoria Lease37425c32012-10-16 16:08:48 -07001344 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001345 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001346 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001347 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001348 return null;
1349 } finally {
1350 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001351 }
1352 }
1353
1354 @Override
1355 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1356 String packageName) {
1357 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001358 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1359 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001360 checkPendingIntent(intent);
1361 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001362 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1363 request.getProvider());
1364 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001365
Victoria Lease37425c32012-10-16 16:08:48 -07001366 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001367
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001368 // geo-fence manager uses the public location API, need to clear identity
1369 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001370 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1371 // temporary measure until geofences work for secondary users
1372 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1373 return;
1374 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001375 long identity = Binder.clearCallingIdentity();
1376 try {
Victoria Lease37425c32012-10-16 16:08:48 -07001377 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001378 } finally {
1379 Binder.restoreCallingIdentity(identity);
1380 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001381 }
1382
1383 @Override
1384 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001385 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001386 checkPendingIntent(intent);
1387 checkPackageName(packageName);
1388
1389 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1390
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001391 // geo-fence manager uses the public location API, need to clear identity
1392 long identity = Binder.clearCallingIdentity();
1393 try {
1394 mGeofenceManager.removeFence(geofence, intent);
1395 } finally {
1396 Binder.restoreCallingIdentity(identity);
1397 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001398 }
1399
1400
1401 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001402 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001403 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 return false;
1405 }
Victoria Lease37425c32012-10-16 16:08:48 -07001406 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1407 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001409 final int uid = Binder.getCallingUid();
1410 final long ident = Binder.clearCallingIdentity();
1411 try {
1412 if (mAppOps.noteOp(AppOpsManager.OP_LOCATION, uid, packageName)
1413 != AppOpsManager.MODE_ALLOWED) {
1414 return false;
1415 }
1416 } finally {
1417 Binder.restoreCallingIdentity(ident);
1418 }
1419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001421 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001423 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 return false;
1425 }
1426 return true;
1427 }
1428
Nick Pellye0fd6932012-07-11 10:26:13 -07001429 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001431 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001432 try {
1433 mGpsStatusProvider.removeGpsStatusListener(listener);
1434 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001435 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001436 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 }
1438 }
1439
Nick Pellye0fd6932012-07-11 10:26:13 -07001440 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001442 if (provider == null) {
1443 // throw NullPointerException to remain compatible with previous implementation
1444 throw new NullPointerException();
1445 }
Victoria Lease37425c32012-10-16 16:08:48 -07001446 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1447 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001450 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 != PackageManager.PERMISSION_GRANTED)) {
1452 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1453 }
1454
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001455 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001456 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001457 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001458
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001459 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 }
1461 }
1462
Nick Pellye0fd6932012-07-11 10:26:13 -07001463 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001464 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001465 if (Binder.getCallingUid() != Process.myUid()) {
1466 throw new SecurityException(
1467 "calling sendNiResponse from outside of the system is not allowed");
1468 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001469 try {
1470 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001471 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001472 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001473 return false;
1474 }
1475 }
1476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001478 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001479 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 * accessed by the caller
1481 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001482 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001483 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001484 if (mProvidersByName.get(provider) == null) {
1485 return null;
1486 }
1487
Victoria Lease37425c32012-10-16 16:08:48 -07001488 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1489 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001491 LocationProviderInterface p;
1492 synchronized (mLock) {
1493 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 }
1495
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001496 if (p == null) return null;
1497 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 }
1499
Nick Pellye0fd6932012-07-11 10:26:13 -07001500 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001502 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1503 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001504 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1505
Victoria Lease269518e2012-10-29 08:25:39 -07001506 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001507 try {
1508 synchronized (mLock) {
1509 LocationProviderInterface p = mProvidersByName.get(provider);
1510 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001511
Victoria Lease269518e2012-10-29 08:25:39 -07001512 return isAllowedBySettingsLocked(provider, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -07001513 }
1514 } finally {
1515 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001516 }
1517 }
1518
1519 private void checkCallerIsProvider() {
1520 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1521 == PackageManager.PERMISSION_GRANTED) {
1522 return;
1523 }
1524
1525 // Previously we only used the INSTALL_LOCATION_PROVIDER
1526 // check. But that is system or signature
1527 // protection level which is not flexible enough for
1528 // providers installed oustide the system image. So
1529 // also allow providers with a UID matching the
1530 // currently bound package name
1531
1532 int uid = Binder.getCallingUid();
1533
1534 if (mGeocodeProvider != null) {
1535 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1536 }
1537 for (LocationProviderProxy proxy : mProxyProviders) {
1538 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1539 }
1540 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1541 "or UID of a currently bound location provider");
1542 }
1543
1544 private boolean doesPackageHaveUid(int uid, String packageName) {
1545 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 return false;
1547 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001548 try {
1549 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1550 if (appInfo.uid != uid) {
1551 return false;
1552 }
1553 } catch (NameNotFoundException e) {
1554 return false;
1555 }
1556 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 }
1558
Nick Pellye0fd6932012-07-11 10:26:13 -07001559 @Override
Mike Lockwooda4903f252010-02-17 06:42:23 -05001560 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001561 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001562
Nick Pelly2eeeec22012-07-18 13:13:37 -07001563 if (!location.isComplete()) {
1564 Log.w(TAG, "Dropping incomplete location: " + location);
1565 return;
1566 }
1567
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001568 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1569 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f252010-02-17 06:42:23 -05001570 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001571 mLocationHandler.sendMessageAtFrontOfQueue(m);
1572 }
1573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574
Laurent Tu75defb62012-11-01 16:21:52 -07001575 private static boolean shouldBroadcastSafe(
1576 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 // Always broadcast the first update
1578 if (lastLoc == null) {
1579 return true;
1580 }
1581
Nick Pellyf1be6862012-05-15 10:53:42 -07001582 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001583 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001584 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001585 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 return false;
1587 }
1588
1589 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001590 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 if (minDistance > 0.0) {
1592 if (loc.distanceTo(lastLoc) <= minDistance) {
1593 return false;
1594 }
1595 }
1596
Laurent Tu75defb62012-11-01 16:21:52 -07001597 // Check whether sufficient number of udpates is left
1598 if (record.mRequest.getNumUpdates() <= 0) {
1599 return false;
1600 }
1601
1602 // Check whether the expiry date has passed
1603 if (record.mRequest.getExpireAt() < now) {
1604 return false;
1605 }
1606
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 return true;
1608 }
1609
Mike Lockwooda4903f252010-02-17 06:42:23 -05001610 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001611 if (D) Log.d(TAG, "incoming location: " + location);
1612
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001613 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f252010-02-17 06:42:23 -05001614 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615
Laurent Tu60ec50a2012-10-04 17:00:10 -07001616 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001617 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001618 if (p == null) return;
1619
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001620 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001621 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1622 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001623 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001624 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001625 lastLocation = new Location(provider);
1626 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001627 } else {
1628 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1629 if (noGPSLocation == null && lastNoGPSLocation != null) {
1630 // New location has no no-GPS location: adopt last no-GPS location. This is set
1631 // directly into location because we do not want to notify COARSE clients.
1632 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1633 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001634 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001635 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636
Laurent Tu60ec50a2012-10-04 17:00:10 -07001637 // Skip if there are no UpdateRecords for this provider.
1638 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1639 if (records == null || records.size() == 0) return;
1640
Victoria Lease09016ab2012-09-16 12:33:15 -07001641 // Fetch coarse location
1642 Location coarseLocation = null;
1643 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1644 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1645 }
1646
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 // Fetch latest status update time
1648 long newStatusUpdateTime = p.getStatusUpdateTime();
1649
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001650 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 Bundle extras = new Bundle();
1652 int status = p.getStatus(extras);
1653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001655 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001657 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001658 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001660 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001661
Victoria Lease269518e2012-10-29 08:25:39 -07001662 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1663 if (receiverUserId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001664 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001665 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001666 " (current user: " + mCurrentUserId + ", app: " +
1667 receiver.mPackageName + ")");
1668 }
1669 continue;
1670 }
1671
Nick Pelly4035f5a2012-08-17 14:43:49 -07001672 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1673 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1674 receiver.mPackageName);
1675 continue;
1676 }
1677
Victoria Lease09016ab2012-09-16 12:33:15 -07001678 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001679 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1680 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001681 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001682 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001683 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001684 if (notifyLocation != null) {
1685 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001686 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001687 if (lastLoc == null) {
1688 lastLoc = new Location(notifyLocation);
1689 r.mLastFixBroadcast = lastLoc;
1690 } else {
1691 lastLoc.set(notifyLocation);
1692 }
1693 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1694 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1695 receiverDead = true;
1696 }
Laurent Tu75defb62012-11-01 16:21:52 -07001697 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 }
1699 }
1700
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001701 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001703 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001705 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001707 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001708 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001709 }
1710 }
1711
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001712 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001713 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001714 if (deadUpdateRecords == null) {
1715 deadUpdateRecords = new ArrayList<UpdateRecord>();
1716 }
1717 deadUpdateRecords.add(r);
1718 }
1719 // track dead receivers
1720 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001721 if (deadReceivers == null) {
1722 deadReceivers = new ArrayList<Receiver>();
1723 }
1724 if (!deadReceivers.contains(receiver)) {
1725 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 }
1727 }
1728 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001729
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001730 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001732 for (Receiver receiver : deadReceivers) {
1733 removeUpdatesLocked(receiver);
1734 }
1735 }
1736 if (deadUpdateRecords != null) {
1737 for (UpdateRecord r : deadUpdateRecords) {
1738 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 }
Victoria Lease8b38b292012-12-04 15:04:43 -08001740 applyRequirementsLocked(provider);
1741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 }
1743
1744 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001745 public LocationWorkerHandler(Looper looper) {
1746 super(looper, null, true);
1747 }
1748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001749 @Override
1750 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001751 switch (msg.what) {
1752 case MSG_LOCATION_CHANGED:
1753 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1754 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 }
1756 }
1757 }
1758
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001759 private void handleLocationChanged(Location location, boolean passive) {
1760 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001761
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001762 if (!passive) {
1763 // notify passive provider of the new location
1764 mPassiveProvider.updateLocation(location);
1765 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001767 synchronized (mLock) {
Victoria Lease269518e2012-10-29 08:25:39 -07001768 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001769 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773
Mike Lockwoode97ae402010-09-29 15:23:46 -04001774 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1775 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001776 public void onPackageDisappeared(String packageName, int reason) {
1777 // remove all receivers associated with this package name
1778 synchronized (mLock) {
1779 ArrayList<Receiver> deadReceivers = null;
1780
1781 for (Receiver receiver : mReceivers.values()) {
1782 if (receiver.mPackageName.equals(packageName)) {
1783 if (deadReceivers == null) {
1784 deadReceivers = new ArrayList<Receiver>();
1785 }
1786 deadReceivers.add(receiver);
1787 }
1788 }
1789
1790 // perform removal outside of mReceivers loop
1791 if (deadReceivers != null) {
1792 for (Receiver receiver : deadReceivers) {
1793 removeUpdatesLocked(receiver);
1794 }
1795 }
1796 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001797 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001798 };
1799
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800 // Wake locks
1801
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001802 private void incrementPendingBroadcasts() {
1803 synchronized (mWakeLock) {
1804 if (mPendingBroadcasts++ == 0) {
1805 try {
1806 mWakeLock.acquire();
1807 log("Acquired wakelock");
1808 } catch (Exception e) {
1809 // This is to catch a runtime exception thrown when we try to release an
1810 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001811 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001812 }
1813 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001814 }
1815 }
1816
1817 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001818 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001819 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001820 try {
1821 // Release wake lock
1822 if (mWakeLock.isHeld()) {
1823 mWakeLock.release();
1824 log("Released wakelock");
1825 } else {
1826 log("Can't release wakelock again!");
1827 }
1828 } catch (Exception e) {
1829 // This is to catch a runtime exception thrown when we try to release an
1830 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001831 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001832 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001833 }
1834 }
1835 }
1836
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 // Geocoder
1838
Nick Pellye0fd6932012-07-11 10:26:13 -07001839 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001840 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001841 return mGeocodeProvider != null;
1842 }
1843
Nick Pellye0fd6932012-07-11 10:26:13 -07001844 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001846 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001847 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001848 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1849 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001851 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 }
1853
Mike Lockwooda55c3212009-04-15 11:10:11 -04001854
Nick Pellye0fd6932012-07-11 10:26:13 -07001855 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001857 double lowerLeftLatitude, double lowerLeftLongitude,
1858 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001859 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001860
1861 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001862 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1863 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1864 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001866 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001867 }
1868
1869 // Mock Providers
1870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 private void checkMockPermissionsSafe() {
1872 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1873 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1874 if (!allowMocks) {
1875 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1876 }
1877
1878 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1879 PackageManager.PERMISSION_GRANTED) {
1880 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001881 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 }
1883
Nick Pellye0fd6932012-07-11 10:26:13 -07001884 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001885 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 checkMockPermissionsSafe();
1887
Mike Lockwooda4903f252010-02-17 06:42:23 -05001888 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1889 throw new IllegalArgumentException("Cannot mock the passive location provider");
1890 }
1891
Mike Lockwood86328a92009-10-23 08:38:25 -04001892 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001893 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001894 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001895 // remove the real provider if we are replacing GPS or network provider
1896 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001897 || LocationManager.NETWORK_PROVIDER.equals(name)
1898 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001899 LocationProviderInterface p = mProvidersByName.get(name);
1900 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001901 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001902 }
1903 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001904 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1906 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001907 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001908 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001909 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 updateProvidersLocked();
1911 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001912 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 }
1914
Nick Pellye0fd6932012-07-11 10:26:13 -07001915 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 public void removeTestProvider(String provider) {
1917 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001918 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09001919 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001920 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001921 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1922 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001923 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001924 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001925
1926 // reinstate real provider if available
1927 LocationProviderInterface realProvider = mRealProviders.get(provider);
1928 if (realProvider != null) {
1929 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001930 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001931 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001932 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001933 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001934 }
1935 }
1936
Nick Pellye0fd6932012-07-11 10:26:13 -07001937 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 public void setTestProviderLocation(String provider, Location loc) {
1939 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001940 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001941 MockProvider mockProvider = mMockProviders.get(provider);
1942 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1944 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001945 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1946 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001947 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001948 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001949 }
1950 }
1951
Nick Pellye0fd6932012-07-11 10:26:13 -07001952 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 public void clearTestProviderLocation(String provider) {
1954 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001955 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001956 MockProvider mockProvider = mMockProviders.get(provider);
1957 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1959 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001960 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001961 }
1962 }
1963
Nick Pellye0fd6932012-07-11 10:26:13 -07001964 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 public void setTestProviderEnabled(String provider, boolean enabled) {
1966 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001967 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001968 MockProvider mockProvider = mMockProviders.get(provider);
1969 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1971 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001972 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001974 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 mEnabledProviders.add(provider);
1976 mDisabledProviders.remove(provider);
1977 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001978 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 mEnabledProviders.remove(provider);
1980 mDisabledProviders.add(provider);
1981 }
1982 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001983 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 }
1985 }
1986
Nick Pellye0fd6932012-07-11 10:26:13 -07001987 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 public void clearTestProviderEnabled(String provider) {
1989 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001990 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001991 MockProvider mockProvider = mMockProviders.get(provider);
1992 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1994 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001995 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 mEnabledProviders.remove(provider);
1997 mDisabledProviders.remove(provider);
1998 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001999 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
2001 }
2002
Nick Pellye0fd6932012-07-11 10:26:13 -07002003 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2005 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002006 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002007 MockProvider mockProvider = mMockProviders.get(provider);
2008 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2010 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002011 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 }
2013 }
2014
Nick Pellye0fd6932012-07-11 10:26:13 -07002015 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002016 public void clearTestProviderStatus(String provider) {
2017 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002018 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002019 MockProvider mockProvider = mMockProviders.get(provider);
2020 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2022 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002023 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 }
2025 }
2026
2027 private void log(String log) {
2028 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002029 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 }
2031 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002032
2033 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002034 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2035 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2036 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002037 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002038 + Binder.getCallingPid()
2039 + ", uid=" + Binder.getCallingUid());
2040 return;
2041 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002042
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002043 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002046 for (Receiver receiver : mReceivers.values()) {
2047 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002049 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002050 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2051 pw.println(" " + entry.getKey() + ":");
2052 for (UpdateRecord record : entry.getValue()) {
2053 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 }
2055 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002057 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2058 String provider = entry.getKey();
2059 Location location = entry.getValue();
2060 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002062
Nick Pellye0fd6932012-07-11 10:26:13 -07002063 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002065 if (mEnabledProviders.size() > 0) {
2066 pw.println(" Enabled Providers:");
2067 for (String i : mEnabledProviders) {
2068 pw.println(" " + i);
2069 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002071 }
2072 if (mDisabledProviders.size() > 0) {
2073 pw.println(" Disabled Providers:");
2074 for (String i : mDisabledProviders) {
2075 pw.println(" " + i);
2076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002077 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002078 pw.append(" ");
2079 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002080 if (mMockProviders.size() > 0) {
2081 pw.println(" Mock Providers:");
2082 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002083 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002084 }
2085 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002086
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002087 pw.append(" fudger: ");
2088 mLocationFudger.dump(fd, pw, args);
2089
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002090 if (args.length > 0 && "short".equals(args[0])) {
2091 return;
2092 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002093 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002094 pw.print(provider.getName() + " Internal State");
2095 if (provider instanceof LocationProviderProxy) {
2096 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2097 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002098 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002099 pw.println(":");
2100 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002101 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002102 }
2103 }
2104}