blob: 5a8be7b2b60b153db3181a90a7ba6bb25c8fad9f [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;
50import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070051import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.Message;
53import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070054import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070056import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070057import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070058import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.provider.Settings;
Tom O'Neilla206a0f2016-12-15 10:26:28 -080060import android.text.TextUtils;
61import android.util.EventLog;
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;
Mike Lockwoode97ae402010-09-29 15:23:46 -040064import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070065import com.android.internal.location.ProviderProperties;
66import com.android.internal.location.ProviderRequest;
Dianne Hackborn8d044e82013-04-30 17:24:15 -070067import com.android.internal.os.BackgroundThread;
destradaa1af4b022013-07-12 15:43:36 -070068import com.android.server.location.FlpHardwareProvider;
69import com.android.server.location.FusedProxy;
Mike Lockwood43e33f22010-03-26 10:41:48 -040070import com.android.server.location.GeocoderProxy;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070071import com.android.server.location.GeofenceProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070072import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040073import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070074import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070075import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040076import com.android.server.location.LocationProviderInterface;
77import com.android.server.location.LocationProviderProxy;
78import com.android.server.location.MockProvider;
79import com.android.server.location.PassiveProvider;
80
81import java.io.FileDescriptor;
82import java.io.PrintWriter;
83import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070084import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040085import java.util.HashMap;
86import java.util.HashSet;
87import java.util.List;
88import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040089import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090
91/**
92 * The service class that manages LocationProviders and issues location
93 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 */
Victoria Lease5cd731a2012-12-19 15:04:21 -080095public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -080097 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -070098
99 private static final String WAKELOCK_KEY = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
Victoria Lease37425c32012-10-16 16:08:48 -0700101 // Location resolution level: no location data whatsoever
102 private static final int RESOLUTION_LEVEL_NONE = 0;
103 // Location resolution level: coarse location data only
104 private static final int RESOLUTION_LEVEL_COARSE = 1;
105 // Location resolution level: fine location data
106 private static final int RESOLUTION_LEVEL_FINE = 2;
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700109 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700111 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400112 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700113 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
114
115 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700116 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700117 private static final String FUSED_LOCATION_SERVICE_ACTION =
118 "com.android.location.service.FusedLocationProvider";
119
120 private static final int MSG_LOCATION_CHANGED = 1;
121
David Christie1b9b7b12013-04-15 15:31:11 -0700122 private static final long NANOS_PER_MILLI = 1000000L;
123
David Christie0b837452013-07-29 16:02:13 -0700124 // The maximum interval a location request can have and still be considered "high power".
125 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
126
Nick Pellyf1be6862012-05-15 10:53:42 -0700127 // Location Providers may sometimes deliver location updates
128 // slightly faster that requested - provide grace period so
129 // we don't unnecessarily filter events that are otherwise on
130 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700131 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700132
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700133 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
134
135 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800136 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700137
138 // used internally for synchronization
139 private final Object mLock = new Object();
140
Victoria Lease5cd731a2012-12-19 15:04:21 -0800141 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700142 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700143 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700144 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700145 private PowerManager mPowerManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700146 private GeocoderProxy mGeocodeProvider;
147 private IGpsStatusProvider mGpsStatusProvider;
148 private INetInitiatedListener mNetInitiatedListener;
149 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700150 private PassiveProvider mPassiveProvider; // track passive provider for special cases
151 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700152
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700153 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 // Set of providers that are explicitly enabled
155 private final Set<String> mEnabledProviders = new HashSet<String>();
156
157 // Set of providers that are explicitly disabled
158 private final Set<String> mDisabledProviders = new HashSet<String>();
159
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160 // Mock (test) providers
161 private final HashMap<String, MockProvider> mMockProviders =
162 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700164 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400165 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500168 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400170
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700171 // real providers, saved here when mocked out
172 private final HashMap<String, LocationProviderInterface> mRealProviders =
173 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700175 // mapping from provider name to provider
176 private final HashMap<String, LocationProviderInterface> mProvidersByName =
177 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700179 // mapping from provider name to all its UpdateRecords
180 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
181 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700182
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 // mapping from provider name to last known location
184 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185
David Christie1b9b7b12013-04-15 15:31:11 -0700186 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
187 // locations stored here are not fudged for coarse permissions.
188 private final HashMap<String, Location> mLastLocationCoarseInterval =
189 new HashMap<String, Location>();
190
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700191 // all providers that operate over proxy, for authorizing incoming location
192 private final ArrayList<LocationProviderProxy> mProxyProviders =
193 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
Victoria Lease38389b62012-09-30 11:44:22 -0700195 // current active user on the device - other users are denied location data
196 private int mCurrentUserId = UserHandle.USER_OWNER;
197
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700198 public LocationManagerService(Context context) {
199 super();
200 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800201 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800202
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700203 if (D) Log.d(TAG, "Constructed");
204
205 // most startup is deferred until systemReady()
206 }
207
Svetoslav Ganova0027152013-06-25 14:59:53 -0700208 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700209 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800210 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700211
Victoria Lease5cd731a2012-12-19 15:04:21 -0800212 // fetch package manager
213 mPackageManager = mContext.getPackageManager();
214
Victoria Lease0aa28602013-05-29 15:28:26 -0700215 // fetch power manager
216 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800217
218 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700219 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800220
221 // prepare mLocationHandler's dependents
222 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
223 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
224 mBlacklist.init();
225 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
226
Dianne Hackbornc2293022013-02-06 23:14:49 -0800227 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700228 AppOpsManager.OnOpChangedListener callback
229 = new AppOpsManager.OnOpChangedInternalListener() {
230 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800231 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700232 for (Receiver receiver : mReceivers.values()) {
233 receiver.updateMonitoring(true);
234 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800235 applyAllProviderRequirementsLocked();
236 }
237 }
238 };
239 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
240
Victoria Lease5cd731a2012-12-19 15:04:21 -0800241 // prepare providers
242 loadProvidersLocked();
243 updateProvidersLocked();
244 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700245
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700246 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700247 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700248 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700249 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800250 @Override
251 public void onChange(boolean selfChange) {
252 synchronized (mLock) {
253 updateProvidersLocked();
254 }
255 }
256 }, UserHandle.USER_ALL);
257 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700258
Victoria Lease38389b62012-09-30 11:44:22 -0700259 // listen for user change
260 IntentFilter intentFilter = new IntentFilter();
261 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
262
263 mContext.registerReceiverAsUser(new BroadcastReceiver() {
264 @Override
265 public void onReceive(Context context, Intent intent) {
266 String action = intent.getAction();
267 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
268 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
269 }
270 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800271 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700272 }
273
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500274 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
275 PackageManager pm = mContext.getPackageManager();
276 String systemPackageName = mContext.getPackageName();
277 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
278
279 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
280 new Intent(FUSED_LOCATION_SERVICE_ACTION),
281 PackageManager.GET_META_DATA, mCurrentUserId);
282 for (ResolveInfo rInfo : rInfos) {
283 String packageName = rInfo.serviceInfo.packageName;
284
285 // Check that the signature is in the list of supported sigs. If it's not in
286 // this list the standard provider binding logic won't bind to it.
287 try {
288 PackageInfo pInfo;
289 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
290 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
291 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
292 ", but has wrong signature, ignoring");
293 continue;
294 }
295 } catch (NameNotFoundException e) {
296 Log.e(TAG, "missing package: " + packageName);
297 continue;
298 }
299
300 // Get the version info
301 if (rInfo.serviceInfo.metaData == null) {
302 Log.w(TAG, "Found fused provider without metadata: " + packageName);
303 continue;
304 }
305
306 int version = rInfo.serviceInfo.metaData.getInt(
307 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
308 if (version == 0) {
309 // This should be the fallback fused location provider.
310
311 // Make sure it's in the system partition.
312 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
313 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
314 continue;
315 }
316
317 // Check that the fallback is signed the same as the OS
318 // as a proxy for coreApp="true"
319 if (pm.checkSignatures(systemPackageName, packageName)
320 != PackageManager.SIGNATURE_MATCH) {
321 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
322 + packageName);
323 continue;
324 }
325
326 // Found a valid fallback.
327 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
328 return;
329 } else {
330 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
331 }
332 }
333
334 throw new IllegalStateException("Unable to find a fused location provider that is in the "
335 + "system partition with version 0 and signed with the platform certificate. "
336 + "Such a package is needed to provide a default fused location provider in the "
337 + "event that no other fused location provider has been installed or is currently "
338 + "available. For example, coreOnly boot mode when decrypting the data "
339 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
340 }
341
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700342 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700343 // create a passive location provider, which is always enabled
344 PassiveProvider passiveProvider = new PassiveProvider(this);
345 addProviderLocked(passiveProvider);
346 mEnabledProviders.add(passiveProvider.getName());
347 mPassiveProvider = passiveProvider;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700348 // Create a gps location provider
349 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
350 mLocationHandler.getLooper());
Victoria Lease5c24fd02012-10-01 11:00:50 -0700351
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700352 if (GpsLocationProvider.isSupported()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700353 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
354 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
355 addProviderLocked(gpsProvider);
356 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
357 }
358
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700359 /*
360 Load package name(s) containing location provider support.
361 These packages can contain services implementing location providers:
362 Geocoder Provider, Network Location Provider, and
363 Fused Location Provider. They will each be searched for
364 service components implementing these providers.
365 The location framework also has support for installation
366 of new location providers at run-time. The new package does not
367 have to be explicitly listed here, however it must have a signature
368 that matches the signature of at least one package on this list.
369 */
370 Resources resources = mContext.getResources();
371 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500372 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700373 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500374 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
375 Arrays.toString(pkgs));
376 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
377
378 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700379
380 // bind to network provider
381 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
382 mContext,
383 LocationManager.NETWORK_PROVIDER,
384 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700385 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
386 com.android.internal.R.string.config_networkLocationProviderPackageName,
387 com.android.internal.R.array.config_locationProviderPackageNames,
388 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700389 if (networkProvider != null) {
390 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
391 mProxyProviders.add(networkProvider);
392 addProviderLocked(networkProvider);
393 } else {
394 Slog.w(TAG, "no network location provider found");
395 }
396
397 // bind to fused provider
398 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
399 mContext,
400 LocationManager.FUSED_PROVIDER,
401 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700402 com.android.internal.R.bool.config_enableFusedLocationOverlay,
403 com.android.internal.R.string.config_fusedLocationProviderPackageName,
404 com.android.internal.R.array.config_locationProviderPackageNames,
405 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700406 if (fusedLocationProvider != null) {
407 addProviderLocked(fusedLocationProvider);
408 mProxyProviders.add(fusedLocationProvider);
409 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700410 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700411 } else {
412 Slog.e(TAG, "no fused location provider found",
413 new IllegalStateException("Location service needs a fused location provider"));
414 }
415
416 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700417 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
418 com.android.internal.R.bool.config_enableGeocoderOverlay,
419 com.android.internal.R.string.config_geocoderProviderPackageName,
420 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800421 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700422 if (mGeocodeProvider == null) {
423 Slog.e(TAG, "no geocoder provider found");
424 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700425
destradaa1af4b022013-07-12 15:43:36 -0700426 // bind to fused provider
destradaa1af4b022013-07-12 15:43:36 -0700427 FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
428 FusedProxy fusedProxy = FusedProxy.createAndBind(
429 mContext,
430 mLocationHandler,
destradaa64be0c62013-08-09 15:01:49 -0700431 flpHardwareProvider.getLocationHardware(),
432 com.android.internal.R.bool.config_enableFusedLocationOverlay,
433 com.android.internal.R.string.config_fusedLocationProviderPackageName,
434 com.android.internal.R.array.config_locationProviderPackageNames);
destradaa1af4b022013-07-12 15:43:36 -0700435 if(fusedProxy == null) {
436 Slog.e(TAG, "No FusedProvider found.");
437 }
destradaa0682809a2013-08-12 18:50:30 -0700438
439 // bind to geofence provider
440 GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
441 com.android.internal.R.bool.config_enableGeofenceOverlay,
442 com.android.internal.R.string.config_geofenceProviderPackageName,
443 com.android.internal.R.array.config_locationProviderPackageNames,
444 mLocationHandler,
445 gpsProvider.getGpsGeofenceProxy(),
446 flpHardwareProvider.getGeofenceHardware());
447 if (provider == null) {
448 Slog.e(TAG, "no geofence provider found");
449 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700450 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700453 * Called when the device's active user changes.
454 * @param userId the new active user's UserId
455 */
456 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700457 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800458 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700459 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700460 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700461 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700462 for (LocationProviderInterface p : mProviders) {
463 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700464 }
Victoria Lease38389b62012-09-30 11:44:22 -0700465 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700466 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700467 }
468 }
469
470 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
472 * location updates.
473 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700474 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700475 final int mUid; // uid of receiver
476 final int mPid; // pid of receiver
477 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700478 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 final ILocationListener mListener;
481 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700482 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700483 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700485
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400486 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700487
David Christie0b837452013-07-29 16:02:13 -0700488 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700489 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700490 // True if app ops has started monitoring this receiver for high power (gps) locations.
491 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700492 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700493 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700495 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700496 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700499 if (listener != null) {
500 mKey = listener.asBinder();
501 } else {
502 mKey = intent;
503 }
Victoria Lease37425c32012-10-16 16:08:48 -0700504 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700505 mUid = uid;
506 mPid = pid;
507 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700508 if (workSource != null && workSource.size() <= 0) {
509 workSource = null;
510 }
511 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700512 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700513
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700514 updateMonitoring(true);
515
Victoria Lease0aa28602013-05-29 15:28:26 -0700516 // construct/configure wakelock
517 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700518 if (workSource == null) {
519 workSource = new WorkSource(mUid, mPackageName);
520 }
521 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 }
523
524 @Override
525 public boolean equals(Object otherObj) {
526 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700527 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 }
529 return false;
530 }
531
532 @Override
533 public int hashCode() {
534 return mKey.hashCode();
535 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 @Override
538 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700539 StringBuilder s = new StringBuilder();
540 s.append("Reciever[");
541 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700543 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700545 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700547 for (String p : mUpdateRecords.keySet()) {
548 s.append(" ").append(mUpdateRecords.get(p).toString());
549 }
550 s.append("]");
551 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 }
553
David Christie15b31912013-08-13 15:54:32 -0700554 /**
555 * Update AppOp monitoring for this receiver.
556 *
557 * @param allow If true receiver is currently active, if false it's been removed.
558 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700559 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700560 if (mHideFromAppOps) {
561 return;
562 }
563
David Christie15b31912013-08-13 15:54:32 -0700564 boolean requestingLocation = false;
565 boolean requestingHighPowerLocation = false;
566 if (allow) {
567 // See if receiver has any enabled update records. Also note if any update records
568 // are high power (has a high power provider with an interval under a threshold).
569 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
570 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
571 requestingLocation = true;
572 LocationProviderInterface locationProvider
573 = mProvidersByName.get(updateRecord.mProvider);
574 ProviderProperties properties = locationProvider != null
575 ? locationProvider.getProperties() : null;
576 if (properties != null
577 && properties.mPowerRequirement == Criteria.POWER_HIGH
578 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
579 requestingHighPowerLocation = true;
580 break;
581 }
582 }
583 }
584 }
585
David Christie0b837452013-07-29 16:02:13 -0700586 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700587 mOpMonitoring = updateMonitoring(
588 requestingLocation,
589 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700590 AppOpsManager.OP_MONITOR_LOCATION);
591
592 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700593 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700594 mOpHighPowerMonitoring = updateMonitoring(
595 requestingHighPowerLocation,
596 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700597 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700598 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700599 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700600 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
601 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
602 }
David Christie0b837452013-07-29 16:02:13 -0700603 }
604
605 /**
606 * Update AppOps monitoring for a single location request and op type.
607 *
608 * @param allowMonitoring True if monitoring is allowed for this request/op.
609 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
610 * @param op AppOps code for the op to update.
611 * @return True if monitoring is on for this request/op after updating.
612 */
613 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
614 int op) {
615 if (!currentlyMonitoring) {
616 if (allowMonitoring) {
617 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
618 == AppOpsManager.MODE_ALLOWED;
619 }
620 } else {
621 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
622 != AppOpsManager.MODE_ALLOWED) {
623 mAppOps.finishOp(op, mUid, mPackageName);
624 return false;
625 }
626 }
627
628 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700629 }
630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 public boolean isListener() {
632 return mListener != null;
633 }
634
635 public boolean isPendingIntent() {
636 return mPendingIntent != null;
637 }
638
639 public ILocationListener getListener() {
640 if (mListener != null) {
641 return mListener;
642 }
643 throw new IllegalStateException("Request for non-existent listener");
644 }
645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
647 if (mListener != null) {
648 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700649 synchronized (this) {
650 // synchronize to ensure incrementPendingBroadcastsLocked()
651 // is called before decrementPendingBroadcasts()
652 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700653 // call this after broadcasting so we do not increment
654 // if we throw an exeption.
655 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700656 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 } catch (RemoteException e) {
658 return false;
659 }
660 } else {
661 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800662 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
664 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700665 synchronized (this) {
666 // synchronize to ensure incrementPendingBroadcastsLocked()
667 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700668 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700669 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700670 // call this after broadcasting so we do not increment
671 // if we throw an exeption.
672 incrementPendingBroadcastsLocked();
673 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 } catch (PendingIntent.CanceledException e) {
675 return false;
676 }
677 }
678 return true;
679 }
680
681 public boolean callLocationChangedLocked(Location location) {
682 if (mListener != null) {
683 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700684 synchronized (this) {
685 // synchronize to ensure incrementPendingBroadcastsLocked()
686 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800687 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700688 // call this after broadcasting so we do not increment
689 // if we throw an exeption.
690 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700691 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 } catch (RemoteException e) {
693 return false;
694 }
695 } else {
696 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800697 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700699 synchronized (this) {
700 // synchronize to ensure incrementPendingBroadcastsLocked()
701 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700702 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700703 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700704 // call this after broadcasting so we do not increment
705 // if we throw an exeption.
706 incrementPendingBroadcastsLocked();
707 }
708 } catch (PendingIntent.CanceledException e) {
709 return false;
710 }
711 }
712 return true;
713 }
714
715 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -0700716 // First update AppOp monitoring.
717 // An app may get/lose location access as providers are enabled/disabled.
718 updateMonitoring(true);
719
Mike Lockwood48f17512009-04-23 09:12:08 -0700720 if (mListener != null) {
721 try {
722 synchronized (this) {
723 // synchronize to ensure incrementPendingBroadcastsLocked()
724 // is called before decrementPendingBroadcasts()
725 if (enabled) {
726 mListener.onProviderEnabled(provider);
727 } else {
728 mListener.onProviderDisabled(provider);
729 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700730 // call this after broadcasting so we do not increment
731 // if we throw an exeption.
732 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700733 }
734 } catch (RemoteException e) {
735 return false;
736 }
737 } else {
738 Intent providerIntent = new Intent();
739 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
740 try {
741 synchronized (this) {
742 // synchronize to ensure incrementPendingBroadcastsLocked()
743 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700744 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700745 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700746 // call this after broadcasting so we do not increment
747 // if we throw an exeption.
748 incrementPendingBroadcastsLocked();
749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 } catch (PendingIntent.CanceledException e) {
751 return false;
752 }
753 }
754 return true;
755 }
756
Nick Pellyf1be6862012-05-15 10:53:42 -0700757 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700759 if (D) Log.d(TAG, "Location listener died");
760
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400761 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 removeUpdatesLocked(this);
763 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700764 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700765 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700766 }
767 }
768
Nick Pellye0fd6932012-07-11 10:26:13 -0700769 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700770 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
771 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400772 synchronized (this) {
773 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700774 }
775 }
776
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400777 // this must be called while synchronized by caller in a synchronized block
778 // containing the sending of the broadcaset
779 private void incrementPendingBroadcastsLocked() {
780 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700781 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400782 }
783 }
784
785 private void decrementPendingBroadcastsLocked() {
786 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700787 if (mWakeLock.isHeld()) {
788 mWakeLock.release();
789 }
790 }
791 }
792
793 public void clearPendingBroadcastsLocked() {
794 if (mPendingBroadcasts > 0) {
795 mPendingBroadcasts = 0;
796 if (mWakeLock.isHeld()) {
797 mWakeLock.release();
798 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700799 }
800 }
801 }
802
Nick Pellye0fd6932012-07-11 10:26:13 -0700803 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700804 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700805 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400806 //the receiver list if it is not found. If it is not found then the
807 //LocationListener was removed when it had a pending broadcast and should
808 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700809 synchronized (mLock) {
810 IBinder binder = listener.asBinder();
811 Receiver receiver = mReceivers.get(binder);
812 if (receiver != null) {
813 synchronized (receiver) {
814 // so wakelock calls will succeed
815 long identity = Binder.clearCallingIdentity();
816 receiver.decrementPendingBroadcastsLocked();
817 Binder.restoreCallingIdentity(identity);
818 }
819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
821 }
822
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700823 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400824 mProviders.add(provider);
825 mProvidersByName.put(provider.getName(), provider);
826 }
827
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700828 private void removeProviderLocked(LocationProviderInterface provider) {
829 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400830 mProviders.remove(provider);
831 mProvidersByName.remove(provider.getName());
832 }
833
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800834 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800835 * Returns "true" if access to the specified location provider is allowed by the current
836 * user's settings. Access to all location providers is forbidden to non-location-provider
837 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800838 *
839 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800840 * @return
841 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800842 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 if (mEnabledProviders.contains(provider)) {
844 return true;
845 }
846 if (mDisabledProviders.contains(provider)) {
847 return false;
848 }
849 // Use system settings
850 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851
Victoria Leaseb711d572012-10-02 13:14:11 -0700852 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700855 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800856 * Returns "true" if access to the specified location provider is allowed by the specified
857 * user's settings. Access to all location providers is forbidden to non-location-provider
858 * processes belonging to background users.
859 *
860 * @param provider the name of the location provider
861 * @param uid the requestor's UID
862 * @return
863 */
864 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
865 if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) {
866 return false;
867 }
868 return isAllowedByCurrentUserSettingsLocked(provider);
869 }
870
871 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700872 * Returns the permission string associated with the specified resolution level.
873 *
874 * @param resolutionLevel the resolution level
875 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700876 */
Victoria Lease37425c32012-10-16 16:08:48 -0700877 private String getResolutionPermission(int resolutionLevel) {
878 switch (resolutionLevel) {
879 case RESOLUTION_LEVEL_FINE:
880 return android.Manifest.permission.ACCESS_FINE_LOCATION;
881 case RESOLUTION_LEVEL_COARSE:
882 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
883 default:
884 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700886 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700887
Victoria Leaseda479c52012-10-15 15:24:16 -0700888 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700889 * Returns the resolution level allowed to the given PID/UID pair.
890 *
891 * @param pid the PID
892 * @param uid the UID
893 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700894 */
Victoria Lease37425c32012-10-16 16:08:48 -0700895 private int getAllowedResolutionLevel(int pid, int uid) {
896 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
897 pid, uid) == PackageManager.PERMISSION_GRANTED) {
898 return RESOLUTION_LEVEL_FINE;
899 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
900 pid, uid) == PackageManager.PERMISSION_GRANTED) {
901 return RESOLUTION_LEVEL_COARSE;
902 } else {
903 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700904 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700905 }
906
907 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700908 * Returns the resolution level allowed to the caller
909 *
910 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700911 */
Victoria Lease37425c32012-10-16 16:08:48 -0700912 private int getCallerAllowedResolutionLevel() {
913 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
914 }
915
916 /**
917 * Throw SecurityException if specified resolution level is insufficient to use geofences.
918 *
919 * @param allowedResolutionLevel resolution level allowed to caller
920 */
921 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
922 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700923 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
924 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 }
926
Victoria Lease37425c32012-10-16 16:08:48 -0700927 /**
928 * Return the minimum resolution level required to use the specified location provider.
929 *
930 * @param provider the name of the location provider
931 * @return minimum resolution level required for provider
932 */
933 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700934 if (LocationManager.GPS_PROVIDER.equals(provider) ||
935 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
936 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700937 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700938 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
939 LocationManager.FUSED_PROVIDER.equals(provider)) {
940 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700941 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700942 } else {
943 // mock providers
944 LocationProviderInterface lp = mMockProviders.get(provider);
945 if (lp != null) {
946 ProviderProperties properties = lp.getProperties();
947 if (properties != null) {
948 if (properties.mRequiresSatellite) {
949 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700950 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700951 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
952 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700953 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700954 }
955 }
956 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700957 }
Victoria Lease37425c32012-10-16 16:08:48 -0700958 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700959 }
960
Victoria Lease37425c32012-10-16 16:08:48 -0700961 /**
962 * Throw SecurityException if specified resolution level is insufficient to use the named
963 * location provider.
964 *
965 * @param allowedResolutionLevel resolution level allowed to caller
966 * @param providerName the name of the location provider
967 */
968 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
969 String providerName) {
970 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
971 if (allowedResolutionLevel < requiredResolutionLevel) {
972 switch (requiredResolutionLevel) {
973 case RESOLUTION_LEVEL_FINE:
974 throw new SecurityException("\"" + providerName + "\" location provider " +
975 "requires ACCESS_FINE_LOCATION permission.");
976 case RESOLUTION_LEVEL_COARSE:
977 throw new SecurityException("\"" + providerName + "\" location provider " +
978 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
979 default:
980 throw new SecurityException("Insufficient permission for \"" + providerName +
981 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700982 }
983 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700984 }
985
David Christie82edc9b2013-07-19 11:31:42 -0700986 /**
987 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
988 * for battery).
989 */
David Christie40e57822013-07-30 11:36:48 -0700990 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -0700991 mContext.enforceCallingOrSelfPermission(
992 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
993 }
994
David Christie40e57822013-07-30 11:36:48 -0700995 private void checkUpdateAppOpsAllowed() {
996 mContext.enforceCallingOrSelfPermission(
997 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
998 }
999
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001000 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001001 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1002 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001003 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001004 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001005 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001006 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001007 }
1008 return -1;
1009 }
1010
1011 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
1012 int op = resolutionLevelToOp(allowedResolutionLevel);
1013 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001014 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1015 return false;
1016 }
1017 }
1018 return true;
1019 }
1020
1021 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001022 int op = resolutionLevelToOp(allowedResolutionLevel);
1023 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001024 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1025 return false;
1026 }
1027 }
1028 return true;
1029 }
1030
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001031 /**
1032 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -07001033 * fused, also including ones that are not permitted to
1034 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001035 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001036 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001038 ArrayList<String> out;
1039 synchronized (mLock) {
1040 out = new ArrayList<String>(mProviders.size());
1041 for (LocationProviderInterface provider : mProviders) {
1042 String name = provider.getName();
1043 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001044 continue;
1045 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 out.add(name);
1047 }
1048 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001049
1050 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 return out;
1052 }
1053
Mike Lockwood03ca2162010-04-01 08:10:09 -07001054 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001055 * Return all providers by name, that match criteria and are optionally
1056 * enabled.
1057 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001058 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001059 @Override
1060 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001061 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001062 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001063 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -07001064 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001065 try {
1066 synchronized (mLock) {
1067 out = new ArrayList<String>(mProviders.size());
1068 for (LocationProviderInterface provider : mProviders) {
1069 String name = provider.getName();
1070 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001071 continue;
1072 }
Victoria Lease37425c32012-10-16 16:08:48 -07001073 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001074 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001075 continue;
1076 }
1077 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1078 name, provider.getProperties(), criteria)) {
1079 continue;
1080 }
1081 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001082 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001083 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001084 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001085 } finally {
1086 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001087 }
1088
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001089 if (D) Log.d(TAG, "getProviders()=" + out);
1090 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001091 }
1092
1093 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001094 * Return the name of the best provider given a Criteria object.
1095 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001096 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001097 * has been deprecated as well. So this method now uses
1098 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001099 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001100 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001101 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001102 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001103
1104 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001105 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001106 result = pickBest(providers);
1107 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1108 return result;
1109 }
1110 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001111 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001112 result = pickBest(providers);
1113 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1114 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001115 }
1116
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001117 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001118 return null;
1119 }
1120
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001121 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001122 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001123 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001124 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1125 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001126 } else {
1127 return providers.get(0);
1128 }
1129 }
1130
Nick Pellye0fd6932012-07-11 10:26:13 -07001131 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001132 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1133 LocationProviderInterface p = mProvidersByName.get(provider);
1134 if (p == null) {
1135 throw new IllegalArgumentException("provider=" + provider);
1136 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001137
1138 boolean result = LocationProvider.propertiesMeetCriteria(
1139 p.getName(), p.getProperties(), criteria);
1140 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1141 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001142 }
1143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001145 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001146 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001147 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 boolean isEnabled = p.isEnabled();
1149 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001150 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001152 updateProviderListenersLocked(name, false, mCurrentUserId);
David Christie75c55f92013-12-18 14:33:57 -08001153 // If any provider has been disabled, clear all last locations for all providers.
1154 // This is to be on the safe side in case a provider has location derived from
1155 // this disabled provider.
1156 mLastLocation.clear();
1157 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001158 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001160 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001161 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001163 }
1164 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001165 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1166 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001167 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1168 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 }
1170 }
1171
Victoria Leaseb711d572012-10-02 13:14:11 -07001172 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 int listeners = 0;
1174
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001175 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001176 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177
1178 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1181 if (records != null) {
1182 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001183 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -07001185 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001186 // Sends a notification message to the receiver
1187 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1188 if (deadReceivers == null) {
1189 deadReceivers = new ArrayList<Receiver>();
1190 }
1191 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001193 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 }
1196 }
1197
1198 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001199 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 removeUpdatesLocked(deadReceivers.get(i));
1201 }
1202 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 if (enabled) {
1205 p.enable();
1206 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001207 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 }
1209 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 }
1213
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001214 private void applyRequirementsLocked(String provider) {
1215 LocationProviderInterface p = mProvidersByName.get(provider);
1216 if (p == null) return;
1217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001219 WorkSource worksource = new WorkSource();
1220 ProviderRequest providerRequest = new ProviderRequest();
1221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001223 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001224 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001225 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1226 record.mReceiver.mAllowedResolutionLevel)) {
1227 LocationRequest locationRequest = record.mRequest;
1228 providerRequest.locationRequests.add(locationRequest);
1229 if (locationRequest.getInterval() < providerRequest.interval) {
1230 providerRequest.reportLocation = true;
1231 providerRequest.interval = locationRequest.getInterval();
1232 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001233 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001234 }
1235 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236
1237 if (providerRequest.reportLocation) {
1238 // calculate who to blame for power
1239 // This is somewhat arbitrary. We pick a threshold interval
1240 // that is slightly higher that the minimum interval, and
1241 // spread the blame across all applications with a request
1242 // under that threshold.
1243 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1244 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001245 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001246 LocationRequest locationRequest = record.mRequest;
1247 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001248 if (record.mReceiver.mWorkSource != null
1249 && record.mReceiver.mWorkSource.size() > 0
1250 && record.mReceiver.mWorkSource.getName(0) != null) {
David Christie82edc9b2013-07-19 11:31:42 -07001251 // Assign blame to another work source.
David Christiee55c9682013-08-22 10:10:34 -07001252 // Can only assign blame if the WorkSource contains names.
David Christie82edc9b2013-07-19 11:31:42 -07001253 worksource.add(record.mReceiver.mWorkSource);
1254 } else {
1255 // Assign blame to caller.
1256 worksource.add(
1257 record.mReceiver.mUid,
1258 record.mReceiver.mPackageName);
1259 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001260 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001261 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001262 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 }
1264 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001265
1266 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1267 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 }
1269
1270 private class UpdateRecord {
1271 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001272 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001274 Location mLastFixBroadcast;
1275 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276
1277 /**
1278 * Note: must be constructed with lock held.
1279 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001280 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001282 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284
1285 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1286 if (records == null) {
1287 records = new ArrayList<UpdateRecord>();
1288 mRecordsByProvider.put(provider, records);
1289 }
1290 if (!records.contains(this)) {
1291 records.add(this);
1292 }
1293 }
1294
1295 /**
1296 * Method to be called when a record will no longer be used. Calling this multiple times
1297 * must have the same effect as calling it once.
1298 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001299 void disposeLocked(boolean removeReceiver) {
1300 // remove from mRecordsByProvider
1301 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1302 if (globalRecords != null) {
1303 globalRecords.remove(this);
1304 }
1305
1306 if (!removeReceiver) return; // the caller will handle the rest
1307
1308 // remove from Receiver#mUpdateRecords
1309 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1310 if (receiverRecords != null) {
1311 receiverRecords.remove(this.mProvider);
1312
1313 // and also remove the Receiver if it has no more update records
1314 if (removeReceiver && receiverRecords.size() == 0) {
1315 removeUpdatesLocked(mReceiver);
1316 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001317 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 }
1319
1320 @Override
1321 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001322 StringBuilder s = new StringBuilder();
1323 s.append("UpdateRecord[");
1324 s.append(mProvider);
1325 s.append(' ').append(mReceiver.mPackageName).append('(');
1326 s.append(mReceiver.mUid).append(')');
1327 s.append(' ').append(mRequest);
1328 s.append(']');
1329 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 }
1332
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001333 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001334 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001335 IBinder binder = listener.asBinder();
1336 Receiver receiver = mReceivers.get(binder);
1337 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001338 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1339 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001340 mReceivers.put(binder, receiver);
1341
1342 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001343 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001344 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001345 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001346 return null;
1347 }
1348 }
1349 return receiver;
1350 }
1351
David Christie82edc9b2013-07-19 11:31:42 -07001352 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001353 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001354 Receiver receiver = mReceivers.get(intent);
1355 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001356 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1357 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001358 mReceivers.put(intent, receiver);
1359 }
1360 return receiver;
1361 }
1362
Victoria Lease37425c32012-10-16 16:08:48 -07001363 /**
1364 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1365 * and consistency requirements.
1366 *
1367 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001368 * @return a version of request that meets the given resolution and consistency requirements
1369 * @hide
1370 */
1371 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1372 LocationRequest sanitizedRequest = new LocationRequest(request);
1373 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1374 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001375 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001376 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001377 break;
1378 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001379 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001380 break;
1381 }
1382 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001383 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1384 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001385 }
Victoria Lease37425c32012-10-16 16:08:48 -07001386 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1387 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001388 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001389 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001390 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001391 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001392 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001393 }
Victoria Lease37425c32012-10-16 16:08:48 -07001394 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001395 }
1396
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001397 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001398 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001399 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001400 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001401 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001402 String[] packages = mPackageManager.getPackagesForUid(uid);
1403 if (packages == null) {
1404 throw new SecurityException("invalid UID " + uid);
1405 }
1406 for (String pkg : packages) {
1407 if (packageName.equals(pkg)) return;
1408 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001409 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001410 }
1411
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001412 private void checkPendingIntent(PendingIntent intent) {
1413 if (intent == null) {
1414 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001415 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001416 }
1417
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001418 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07001419 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001420 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001421 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001422 } else if (intent != null && listener != null) {
1423 throw new IllegalArgumentException("cannot register both listener and intent");
1424 } else if (intent != null) {
1425 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07001426 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001427 } else {
David Christie40e57822013-07-30 11:36:48 -07001428 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001429 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001430 }
1431
Nick Pellye0fd6932012-07-11 10:26:13 -07001432 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001433 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1434 PendingIntent intent, String packageName) {
1435 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1436 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001437 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1438 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1439 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001440 WorkSource workSource = request.getWorkSource();
1441 if (workSource != null && workSource.size() > 0) {
David Christie40e57822013-07-30 11:36:48 -07001442 checkDeviceStatsAllowed();
1443 }
1444 boolean hideFromAppOps = request.getHideFromAppOps();
1445 if (hideFromAppOps) {
1446 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07001447 }
Victoria Lease37425c32012-10-16 16:08:48 -07001448 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001450 final int pid = Binder.getCallingPid();
1451 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001452 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 long identity = Binder.clearCallingIdentity();
1454 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001455 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1456 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001457 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001458
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001459 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001460 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07001461 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07001462 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001463 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 } finally {
1465 Binder.restoreCallingIdentity(identity);
1466 }
1467 }
1468
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001469 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1470 int pid, int uid, String packageName) {
1471 // Figure out the provider. Either its explicitly request (legacy use cases), or
1472 // use the fused provider
1473 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1474 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001475 if (name == null) {
1476 throw new IllegalArgumentException("provider name must not be null");
1477 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001478
1479 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1480 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001481 LocationProviderInterface provider = mProvidersByName.get(name);
1482 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07001483 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001484 }
1485
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001486 UpdateRecord record = new UpdateRecord(name, request, receiver);
1487 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1488 if (oldRecord != null) {
1489 oldRecord.disposeLocked(false);
1490 }
1491
Victoria Lease09eeaec2013-02-05 11:34:13 -08001492 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001493 if (isProviderEnabled) {
1494 applyRequirementsLocked(name);
1495 } else {
1496 // Notify the listener that updates are currently disabled
1497 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 }
David Christie0b837452013-07-29 16:02:13 -07001499 // Update the monitoring here just in case multiple location requests were added to the
1500 // same receiver (this request may be high power and the initial might not have been).
1501 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 }
1503
Nick Pellye0fd6932012-07-11 10:26:13 -07001504 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001505 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1506 String packageName) {
1507 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001508
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001509 final int pid = Binder.getCallingPid();
1510 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001511
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001512 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07001513 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07001514 boolean hideFromAppOps = false;
1515 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1516 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001517
1518 // providers may use public location API's, need to clear identity
1519 long identity = Binder.clearCallingIdentity();
1520 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001521 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001522 } finally {
1523 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 }
1526 }
1527
1528 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001529 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001530
1531 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1532 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1533 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001534 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001535 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 }
1537
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001538 receiver.updateMonitoring(false);
1539
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001540 // Record which providers were associated with this listener
1541 HashSet<String> providers = new HashSet<String>();
1542 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1543 if (oldRecords != null) {
1544 // Call dispose() on the obsolete update records.
1545 for (UpdateRecord record : oldRecords.values()) {
1546 record.disposeLocked(false);
1547 }
1548 // Accumulate providers
1549 providers.addAll(oldRecords.keySet());
1550 }
1551
1552 // update provider
1553 for (String provider : providers) {
1554 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001555 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001556 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 }
1558
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001559 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 }
1561 }
1562
Dianne Hackbornc2293022013-02-06 23:14:49 -08001563 private void applyAllProviderRequirementsLocked() {
1564 for (LocationProviderInterface p : mProviders) {
1565 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001566 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001567 continue;
1568 }
1569
1570 applyRequirementsLocked(p.getName());
1571 }
1572 }
1573
Nick Pellye0fd6932012-07-11 10:26:13 -07001574 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001575 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001576 if (D) Log.d(TAG, "getLastLocation: " + request);
1577 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001578 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001579 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001580 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1581 request.getProvider());
1582 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001583
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001584 final int uid = Binder.getCallingUid();
1585 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001586 try {
1587 if (mBlacklist.isBlacklisted(packageName)) {
1588 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1589 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001590 return null;
1591 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001592
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001593 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1594 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1595 packageName);
1596 return null;
1597 }
1598
Victoria Leaseb711d572012-10-02 13:14:11 -07001599 synchronized (mLock) {
1600 // Figure out the provider. Either its explicitly request (deprecated API's),
1601 // or use the fused provider
1602 String name = request.getProvider();
1603 if (name == null) name = LocationManager.FUSED_PROVIDER;
1604 LocationProviderInterface provider = mProvidersByName.get(name);
1605 if (provider == null) return null;
1606
Victoria Lease09eeaec2013-02-05 11:34:13 -08001607 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001608
David Christie1b9b7b12013-04-15 15:31:11 -07001609 Location location;
1610 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1611 // Make sure that an app with coarse permissions can't get frequent location
1612 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1613 location = mLastLocationCoarseInterval.get(name);
1614 } else {
1615 location = mLastLocation.get(name);
1616 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001617 if (location == null) {
1618 return null;
1619 }
Victoria Lease37425c32012-10-16 16:08:48 -07001620 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001621 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1622 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001623 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001624 }
Victoria Lease37425c32012-10-16 16:08:48 -07001625 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001626 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001627 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001628 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001629 return null;
1630 } finally {
1631 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001632 }
1633 }
1634
1635 @Override
1636 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1637 String packageName) {
1638 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001639 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1640 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001641 checkPendingIntent(intent);
1642 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001643 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1644 request.getProvider());
1645 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001646
Victoria Lease37425c32012-10-16 16:08:48 -07001647 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001648
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001649 // geo-fence manager uses the public location API, need to clear identity
1650 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001651 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1652 // temporary measure until geofences work for secondary users
1653 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1654 return;
1655 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001656 long identity = Binder.clearCallingIdentity();
1657 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001658 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1659 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001660 } finally {
1661 Binder.restoreCallingIdentity(identity);
1662 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001663 }
1664
1665 @Override
1666 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001667 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001668 checkPendingIntent(intent);
1669 checkPackageName(packageName);
1670
1671 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1672
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001673 // geo-fence manager uses the public location API, need to clear identity
1674 long identity = Binder.clearCallingIdentity();
1675 try {
1676 mGeofenceManager.removeFence(geofence, intent);
1677 } finally {
1678 Binder.restoreCallingIdentity(identity);
1679 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001680 }
1681
1682
1683 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001684 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001685 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 return false;
1687 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001688 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1689 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001690 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001692 final int uid = Binder.getCallingUid();
1693 final long ident = Binder.clearCallingIdentity();
1694 try {
Victoria Lease3d5173d2013-02-05 16:07:32 -08001695 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001696 return false;
1697 }
1698 } finally {
1699 Binder.restoreCallingIdentity(ident);
1700 }
1701
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001703 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001705 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 return false;
1707 }
1708 return true;
1709 }
1710
Nick Pellye0fd6932012-07-11 10:26:13 -07001711 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001713 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001714 try {
1715 mGpsStatusProvider.removeGpsStatusListener(listener);
1716 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001717 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001718 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 }
1720 }
1721
Nick Pellye0fd6932012-07-11 10:26:13 -07001722 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001724 if (provider == null) {
1725 // throw NullPointerException to remain compatible with previous implementation
1726 throw new NullPointerException();
1727 }
Victoria Lease37425c32012-10-16 16:08:48 -07001728 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1729 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001732 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 != PackageManager.PERMISSION_GRANTED)) {
1734 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1735 }
1736
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001737 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001738 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001739 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001740
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001741 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 }
1743 }
1744
Nick Pellye0fd6932012-07-11 10:26:13 -07001745 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001746 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001747 if (Binder.getCallingUid() != Process.myUid()) {
1748 throw new SecurityException(
1749 "calling sendNiResponse from outside of the system is not allowed");
1750 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001751 try {
1752 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001753 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001754 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001755 return false;
1756 }
1757 }
1758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001760 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001761 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 * accessed by the caller
1763 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001764 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001765 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001766 if (mProvidersByName.get(provider) == null) {
1767 return null;
1768 }
1769
Victoria Lease37425c32012-10-16 16:08:48 -07001770 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1771 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001773 LocationProviderInterface p;
1774 synchronized (mLock) {
1775 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776 }
1777
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001778 if (p == null) return null;
1779 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 }
1781
Nick Pellye0fd6932012-07-11 10:26:13 -07001782 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 public boolean isProviderEnabled(String provider) {
Tom O'Neilld5759432013-09-11 11:03:03 -07001784 // TODO: remove this check in next release, see b/10696351
Victoria Lease37425c32012-10-16 16:08:48 -07001785 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1786 provider);
Tom O'Neilld5759432013-09-11 11:03:03 -07001787
1788 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
1789 // so we discourage its use
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001790 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1791
Victoria Lease09eeaec2013-02-05 11:34:13 -08001792 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001793 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001794 try {
1795 synchronized (mLock) {
1796 LocationProviderInterface p = mProvidersByName.get(provider);
1797 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001798
Victoria Lease09eeaec2013-02-05 11:34:13 -08001799 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001800 }
1801 } finally {
1802 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001803 }
1804 }
1805
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001806 /**
1807 * Returns "true" if the UID belongs to a bound location provider.
1808 *
1809 * @param uid the uid
1810 * @return true if uid belongs to a bound location provider
1811 */
1812 private boolean isUidALocationProvider(int uid) {
1813 if (uid == Process.SYSTEM_UID) {
1814 return true;
1815 }
1816 if (mGeocodeProvider != null) {
1817 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1818 }
1819 for (LocationProviderProxy proxy : mProxyProviders) {
1820 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
1821 }
1822 return false;
1823 }
1824
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001825 private void checkCallerIsProvider() {
1826 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1827 == PackageManager.PERMISSION_GRANTED) {
1828 return;
1829 }
1830
1831 // Previously we only used the INSTALL_LOCATION_PROVIDER
1832 // check. But that is system or signature
1833 // protection level which is not flexible enough for
1834 // providers installed oustide the system image. So
1835 // also allow providers with a UID matching the
1836 // currently bound package name
1837
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001838 if (isUidALocationProvider(Binder.getCallingUid())) {
1839 return;
1840 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001841
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001842 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1843 "or UID of a currently bound location provider");
1844 }
1845
1846 private boolean doesPackageHaveUid(int uid, String packageName) {
1847 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001848 return false;
1849 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001850 try {
1851 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1852 if (appInfo.uid != uid) {
1853 return false;
1854 }
1855 } catch (NameNotFoundException e) {
1856 return false;
1857 }
1858 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859 }
1860
Nick Pellye0fd6932012-07-11 10:26:13 -07001861 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001862 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001863 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001864
Nick Pelly2eeeec22012-07-18 13:13:37 -07001865 if (!location.isComplete()) {
1866 Log.w(TAG, "Dropping incomplete location: " + location);
1867 return;
1868 }
1869
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001870 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1871 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001872 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001873 mLocationHandler.sendMessageAtFrontOfQueue(m);
1874 }
1875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876
Laurent Tu75defb62012-11-01 16:21:52 -07001877 private static boolean shouldBroadcastSafe(
1878 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 // Always broadcast the first update
1880 if (lastLoc == null) {
1881 return true;
1882 }
1883
Nick Pellyf1be6862012-05-15 10:53:42 -07001884 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001885 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07001886 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
1887 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001888 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889 return false;
1890 }
1891
1892 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001893 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 if (minDistance > 0.0) {
1895 if (loc.distanceTo(lastLoc) <= minDistance) {
1896 return false;
1897 }
1898 }
1899
Laurent Tu75defb62012-11-01 16:21:52 -07001900 // Check whether sufficient number of udpates is left
1901 if (record.mRequest.getNumUpdates() <= 0) {
1902 return false;
1903 }
1904
1905 // Check whether the expiry date has passed
1906 if (record.mRequest.getExpireAt() < now) {
1907 return false;
1908 }
1909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 return true;
1911 }
1912
Mike Lockwooda4903f22010-02-17 06:42:23 -05001913 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001914 if (D) Log.d(TAG, "incoming location: " + location);
1915
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001916 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001917 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918
Laurent Tu60ec50a2012-10-04 17:00:10 -07001919 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001920 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001921 if (p == null) return;
1922
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001923 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001924 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1925 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001926 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001927 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001928 lastLocation = new Location(provider);
1929 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001930 } else {
1931 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1932 if (noGPSLocation == null && lastNoGPSLocation != null) {
1933 // New location has no no-GPS location: adopt last no-GPS location. This is set
1934 // directly into location because we do not want to notify COARSE clients.
1935 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1936 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001937 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001938 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001939
David Christie1b9b7b12013-04-15 15:31:11 -07001940 // Update last known coarse interval location if enough time has passed.
1941 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
1942 if (lastLocationCoarseInterval == null) {
1943 lastLocationCoarseInterval = new Location(location);
1944 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
1945 }
1946 long timeDiffNanos = location.getElapsedRealtimeNanos()
1947 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
1948 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
1949 lastLocationCoarseInterval.set(location);
1950 }
1951 // Don't ever return a coarse location that is more recent than the allowed update
1952 // interval (i.e. don't allow an app to keep registering and unregistering for
1953 // location updates to overcome the minimum interval).
1954 noGPSLocation =
1955 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1956
Laurent Tu60ec50a2012-10-04 17:00:10 -07001957 // Skip if there are no UpdateRecords for this provider.
1958 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1959 if (records == null || records.size() == 0) return;
1960
Victoria Lease09016ab2012-09-16 12:33:15 -07001961 // Fetch coarse location
1962 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07001963 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001964 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1965 }
1966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 // Fetch latest status update time
1968 long newStatusUpdateTime = p.getStatusUpdateTime();
1969
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001970 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 Bundle extras = new Bundle();
1972 int status = p.getStatus(extras);
1973
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001975 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001976
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001978 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001980 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001981
Victoria Lease269518e2012-10-29 08:25:39 -07001982 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Victoria Lease2f5b97c2013-05-07 14:22:02 -07001983 if (receiverUserId != mCurrentUserId && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001984 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001985 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001986 " (current user: " + mCurrentUserId + ", app: " +
1987 receiver.mPackageName + ")");
1988 }
1989 continue;
1990 }
1991
Nick Pelly4035f5a2012-08-17 14:43:49 -07001992 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1993 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1994 receiver.mPackageName);
1995 continue;
1996 }
1997
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001998 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
1999 receiver.mAllowedResolutionLevel)) {
2000 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2001 receiver.mPackageName);
2002 continue;
2003 }
2004
Victoria Lease09016ab2012-09-16 12:33:15 -07002005 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07002006 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2007 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002008 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002009 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002010 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002011 if (notifyLocation != null) {
2012 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002013 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002014 if (lastLoc == null) {
2015 lastLoc = new Location(notifyLocation);
2016 r.mLastFixBroadcast = lastLoc;
2017 } else {
2018 lastLoc.set(notifyLocation);
2019 }
2020 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2021 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2022 receiverDead = true;
2023 }
Laurent Tu75defb62012-11-01 16:21:52 -07002024 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 }
2026 }
2027
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002028 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002030 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002032 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002033 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002034 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08002035 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07002036 }
2037 }
2038
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002039 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07002040 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002041 if (deadUpdateRecords == null) {
2042 deadUpdateRecords = new ArrayList<UpdateRecord>();
2043 }
2044 deadUpdateRecords.add(r);
2045 }
2046 // track dead receivers
2047 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002048 if (deadReceivers == null) {
2049 deadReceivers = new ArrayList<Receiver>();
2050 }
2051 if (!deadReceivers.contains(receiver)) {
2052 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 }
2054 }
2055 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002056
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002057 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002059 for (Receiver receiver : deadReceivers) {
2060 removeUpdatesLocked(receiver);
2061 }
2062 }
2063 if (deadUpdateRecords != null) {
2064 for (UpdateRecord r : deadUpdateRecords) {
2065 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 }
Victoria Lease8b38b292012-12-04 15:04:43 -08002067 applyRequirementsLocked(provider);
2068 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 }
2070
2071 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08002072 public LocationWorkerHandler(Looper looper) {
2073 super(looper, null, true);
2074 }
2075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002076 @Override
2077 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002078 switch (msg.what) {
2079 case MSG_LOCATION_CHANGED:
2080 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2081 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002082 }
2083 }
2084 }
2085
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002086 private boolean isMockProvider(String provider) {
2087 synchronized (mLock) {
2088 return mMockProviders.containsKey(provider);
2089 }
2090 }
2091
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002092 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002093 // create a working copy of the incoming Location so that the service can modify it without
2094 // disturbing the caller's copy
2095 Location myLocation = new Location(location);
2096 String provider = myLocation.getProvider();
2097
2098 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2099 // bit if location did not come from a mock provider because passive/fused providers can
2100 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2101 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2102 myLocation.setIsFromMockProvider(true);
2103 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08002104
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002105 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08002106 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2107 if (!passive) {
2108 // notify passive provider of the new location
2109 mPassiveProvider.updateLocation(myLocation);
2110 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002111 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002112 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002113 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002115
Mike Lockwoode97ae402010-09-29 15:23:46 -04002116 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2117 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002118 public void onPackageDisappeared(String packageName, int reason) {
2119 // remove all receivers associated with this package name
2120 synchronized (mLock) {
2121 ArrayList<Receiver> deadReceivers = null;
2122
2123 for (Receiver receiver : mReceivers.values()) {
2124 if (receiver.mPackageName.equals(packageName)) {
2125 if (deadReceivers == null) {
2126 deadReceivers = new ArrayList<Receiver>();
2127 }
2128 deadReceivers.add(receiver);
2129 }
2130 }
2131
2132 // perform removal outside of mReceivers loop
2133 if (deadReceivers != null) {
2134 for (Receiver receiver : deadReceivers) {
2135 removeUpdatesLocked(receiver);
2136 }
2137 }
2138 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002139 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002140 };
2141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002142 // Geocoder
2143
Nick Pellye0fd6932012-07-11 10:26:13 -07002144 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002145 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002146 return mGeocodeProvider != null;
2147 }
2148
Nick Pellye0fd6932012-07-11 10:26:13 -07002149 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002150 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002151 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002152 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002153 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2154 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002156 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002157 }
2158
Mike Lockwooda55c3212009-04-15 11:10:11 -04002159
Nick Pellye0fd6932012-07-11 10:26:13 -07002160 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002162 double lowerLeftLatitude, double lowerLeftLongitude,
2163 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002164 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002165
2166 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002167 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2168 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2169 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002171 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 }
2173
2174 // Mock Providers
2175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002176 private void checkMockPermissionsSafe() {
2177 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2178 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2179 if (!allowMocks) {
2180 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2181 }
2182
2183 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2184 PackageManager.PERMISSION_GRANTED) {
2185 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07002186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002187 }
2188
Nick Pellye0fd6932012-07-11 10:26:13 -07002189 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002190 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002191 checkMockPermissionsSafe();
2192
Mike Lockwooda4903f22010-02-17 06:42:23 -05002193 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2194 throw new IllegalArgumentException("Cannot mock the passive location provider");
2195 }
2196
Mike Lockwood86328a92009-10-23 08:38:25 -04002197 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002198 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002199 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002200 // remove the real provider if we are replacing GPS or network provider
2201 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002202 || LocationManager.NETWORK_PROVIDER.equals(name)
2203 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002204 LocationProviderInterface p = mProvidersByName.get(name);
2205 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002206 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002207 }
2208 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002209 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2211 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002212 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002213 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002214 mLastLocation.put(name, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002215 mLastLocationCoarseInterval.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 updateProvidersLocked();
2217 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002218 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 }
2220
Nick Pellye0fd6932012-07-11 10:26:13 -07002221 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 public void removeTestProvider(String provider) {
2223 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002224 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09002225 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002226 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2228 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002229 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002230 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002231
2232 // reinstate real provider if available
2233 LocationProviderInterface realProvider = mRealProviders.get(provider);
2234 if (realProvider != null) {
2235 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002236 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002237 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002238 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002239 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002240 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002241 }
2242 }
2243
Nick Pellye0fd6932012-07-11 10:26:13 -07002244 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002245 public void setTestProviderLocation(String provider, Location loc) {
2246 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002247 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002248 MockProvider mockProvider = mMockProviders.get(provider);
2249 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2251 }
Tom O'Neilla206a0f2016-12-15 10:26:28 -08002252
2253 // Ensure that the location is marked as being mock. There's some logic to do this in
2254 // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
2255 Location mock = new Location(loc);
2256 mock.setIsFromMockProvider(true);
2257
2258 if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
2259 // The location has an explicit provider that is different from the mock provider
2260 // name. The caller may be trying to fool us via bug 33091107.
2261 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
2262 provider + "!=" + loc.getProvider());
2263 }
2264
Mike Lockwood95427cd2009-05-07 13:27:54 -04002265 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2266 long identity = Binder.clearCallingIdentity();
Tom O'Neilla206a0f2016-12-15 10:26:28 -08002267 mockProvider.setLocation(mock);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002268 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002269 }
2270 }
2271
Nick Pellye0fd6932012-07-11 10:26:13 -07002272 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002273 public void clearTestProviderLocation(String provider) {
2274 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002275 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002276 MockProvider mockProvider = mMockProviders.get(provider);
2277 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002278 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2279 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002280 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002281 }
2282 }
2283
Nick Pellye0fd6932012-07-11 10:26:13 -07002284 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002285 public void setTestProviderEnabled(String provider, boolean enabled) {
2286 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002287 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002288 MockProvider mockProvider = mMockProviders.get(provider);
2289 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002290 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2291 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002292 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002293 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002294 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002295 mEnabledProviders.add(provider);
2296 mDisabledProviders.remove(provider);
2297 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002298 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002299 mEnabledProviders.remove(provider);
2300 mDisabledProviders.add(provider);
2301 }
2302 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002303 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002304 }
2305 }
2306
Nick Pellye0fd6932012-07-11 10:26:13 -07002307 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002308 public void clearTestProviderEnabled(String provider) {
2309 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002310 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002311 MockProvider mockProvider = mMockProviders.get(provider);
2312 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002313 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2314 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002315 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002316 mEnabledProviders.remove(provider);
2317 mDisabledProviders.remove(provider);
2318 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002319 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002320 }
2321 }
2322
Nick Pellye0fd6932012-07-11 10:26:13 -07002323 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2325 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002326 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002327 MockProvider mockProvider = mMockProviders.get(provider);
2328 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002329 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2330 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002331 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002332 }
2333 }
2334
Nick Pellye0fd6932012-07-11 10:26:13 -07002335 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002336 public void clearTestProviderStatus(String provider) {
2337 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002338 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002339 MockProvider mockProvider = mMockProviders.get(provider);
2340 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002341 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2342 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002343 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002344 }
2345 }
2346
2347 private void log(String log) {
2348 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002349 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002350 }
2351 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002352
2353 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002354 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2355 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2356 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002357 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002358 + Binder.getCallingPid()
2359 + ", uid=" + Binder.getCallingUid());
2360 return;
2361 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002362
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002363 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002364 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002365 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002366 for (Receiver receiver : mReceivers.values()) {
2367 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002369 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002370 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2371 pw.println(" " + entry.getKey() + ":");
2372 for (UpdateRecord record : entry.getValue()) {
2373 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002374 }
2375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002376 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002377 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2378 String provider = entry.getKey();
2379 Location location = entry.getValue();
2380 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002381 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002382
David Christie1b9b7b12013-04-15 15:31:11 -07002383 pw.println(" Last Known Locations Coarse Intervals:");
2384 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2385 String provider = entry.getKey();
2386 Location location = entry.getValue();
2387 pw.println(" " + provider + ": " + location);
2388 }
2389
Nick Pellye0fd6932012-07-11 10:26:13 -07002390 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002392 if (mEnabledProviders.size() > 0) {
2393 pw.println(" Enabled Providers:");
2394 for (String i : mEnabledProviders) {
2395 pw.println(" " + i);
2396 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002398 }
2399 if (mDisabledProviders.size() > 0) {
2400 pw.println(" Disabled Providers:");
2401 for (String i : mDisabledProviders) {
2402 pw.println(" " + i);
2403 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002404 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002405 pw.append(" ");
2406 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002407 if (mMockProviders.size() > 0) {
2408 pw.println(" Mock Providers:");
2409 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002410 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002411 }
2412 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002413
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002414 pw.append(" fudger: ");
2415 mLocationFudger.dump(fd, pw, args);
2416
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002417 if (args.length > 0 && "short".equals(args[0])) {
2418 return;
2419 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002420 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002421 pw.print(provider.getName() + " Internal State");
2422 if (provider instanceof LocationProviderProxy) {
2423 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2424 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002425 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002426 pw.println(":");
2427 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002429 }
2430 }
2431}