blob: bde9e1c9515035ea50142891cb6f14f611cb20b4 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080061import android.util.Slog;
Mike Lockwoode97ae402010-09-29 15:23:46 -040062import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070063import com.android.internal.location.ProviderProperties;
64import com.android.internal.location.ProviderRequest;
Dianne Hackborn8d044e82013-04-30 17:24:15 -070065import com.android.internal.os.BackgroundThread;
Mike Lockwood43e33f22010-03-26 10:41:48 -040066import com.android.server.location.GeocoderProxy;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070067import com.android.server.location.GeofenceProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070068import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040069import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070070import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070071import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040072import com.android.server.location.LocationProviderInterface;
73import com.android.server.location.LocationProviderProxy;
74import com.android.server.location.MockProvider;
75import com.android.server.location.PassiveProvider;
76
77import java.io.FileDescriptor;
78import java.io.PrintWriter;
79import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070080import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040081import java.util.HashMap;
82import java.util.HashSet;
83import java.util.List;
84import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040085import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
87/**
88 * The service class that manages LocationProviders and issues location
89 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 */
Victoria Lease5cd731a2012-12-19 15:04:21 -080091public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -080093 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -070094
95 private static final String WAKELOCK_KEY = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
Victoria Lease37425c32012-10-16 16:08:48 -070097 // Location resolution level: no location data whatsoever
98 private static final int RESOLUTION_LEVEL_NONE = 0;
99 // Location resolution level: coarse location data only
100 private static final int RESOLUTION_LEVEL_COARSE = 1;
101 // Location resolution level: fine location data
102 private static final int RESOLUTION_LEVEL_FINE = 2;
103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700105 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700107 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400108 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700109 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
110
111 private static final String NETWORK_LOCATION_SERVICE_ACTION =
112 "com.android.location.service.v2.NetworkLocationProvider";
113 private static final String FUSED_LOCATION_SERVICE_ACTION =
114 "com.android.location.service.FusedLocationProvider";
115
116 private static final int MSG_LOCATION_CHANGED = 1;
117
David Christie1b9b7b12013-04-15 15:31:11 -0700118 private static final long NANOS_PER_MILLI = 1000000L;
119
Nick Pellyf1be6862012-05-15 10:53:42 -0700120 // Location Providers may sometimes deliver location updates
121 // slightly faster that requested - provide grace period so
122 // we don't unnecessarily filter events that are otherwise on
123 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700124 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700125
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700126 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
127
128 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800129 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700130
131 // used internally for synchronization
132 private final Object mLock = new Object();
133
Victoria Lease5cd731a2012-12-19 15:04:21 -0800134 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700135 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700136 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700137 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700138 private PowerManager mPowerManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700139 private GeocoderProxy mGeocodeProvider;
140 private IGpsStatusProvider mGpsStatusProvider;
141 private INetInitiatedListener mNetInitiatedListener;
142 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700143 private PassiveProvider mPassiveProvider; // track passive provider for special cases
144 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700145
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700146 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 // Set of providers that are explicitly enabled
148 private final Set<String> mEnabledProviders = new HashSet<String>();
149
150 // Set of providers that are explicitly disabled
151 private final Set<String> mDisabledProviders = new HashSet<String>();
152
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700153 // Mock (test) providers
154 private final HashMap<String, MockProvider> mMockProviders =
155 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700157 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400158 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500161 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400163
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700164 // real providers, saved here when mocked out
165 private final HashMap<String, LocationProviderInterface> mRealProviders =
166 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700168 // mapping from provider name to provider
169 private final HashMap<String, LocationProviderInterface> mProvidersByName =
170 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172 // mapping from provider name to all its UpdateRecords
173 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
174 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700175
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700176 // mapping from provider name to last known location
177 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
David Christie1b9b7b12013-04-15 15:31:11 -0700179 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
180 // locations stored here are not fudged for coarse permissions.
181 private final HashMap<String, Location> mLastLocationCoarseInterval =
182 new HashMap<String, Location>();
183
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700184 // all providers that operate over proxy, for authorizing incoming location
185 private final ArrayList<LocationProviderProxy> mProxyProviders =
186 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187
Victoria Lease38389b62012-09-30 11:44:22 -0700188 // current active user on the device - other users are denied location data
189 private int mCurrentUserId = UserHandle.USER_OWNER;
190
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700191 public LocationManagerService(Context context) {
192 super();
193 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800194 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 if (D) Log.d(TAG, "Constructed");
197
198 // most startup is deferred until systemReady()
199 }
200
Svetoslav Ganova0027152013-06-25 14:59:53 -0700201 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700202 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800203 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700204
Victoria Lease5cd731a2012-12-19 15:04:21 -0800205 // fetch package manager
206 mPackageManager = mContext.getPackageManager();
207
Victoria Lease0aa28602013-05-29 15:28:26 -0700208 // fetch power manager
209 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800210
211 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700212 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800213
214 // prepare mLocationHandler's dependents
215 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
216 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
217 mBlacklist.init();
218 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
219
Dianne Hackbornc2293022013-02-06 23:14:49 -0800220 // Monitor for app ops mode changes.
221 AppOpsManager.Callback callback = new AppOpsManager.Callback() {
222 public void opChanged(int op, String packageName) {
223 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700224 for (Receiver receiver : mReceivers.values()) {
225 receiver.updateMonitoring(true);
226 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800227 applyAllProviderRequirementsLocked();
228 }
229 }
230 };
231 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
232
Victoria Lease5cd731a2012-12-19 15:04:21 -0800233 // prepare providers
234 loadProvidersLocked();
235 updateProvidersLocked();
236 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700237
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700238 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700239 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700240 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700241 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800242 @Override
243 public void onChange(boolean selfChange) {
244 synchronized (mLock) {
245 updateProvidersLocked();
246 }
247 }
248 }, UserHandle.USER_ALL);
249 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700250
Victoria Lease38389b62012-09-30 11:44:22 -0700251 // listen for user change
252 IntentFilter intentFilter = new IntentFilter();
253 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
254
255 mContext.registerReceiverAsUser(new BroadcastReceiver() {
256 @Override
257 public void onReceive(Context context, Intent intent) {
258 String action = intent.getAction();
259 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
260 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
261 }
262 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800263 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700264 }
265
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500266 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
267 PackageManager pm = mContext.getPackageManager();
268 String systemPackageName = mContext.getPackageName();
269 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
270
271 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
272 new Intent(FUSED_LOCATION_SERVICE_ACTION),
273 PackageManager.GET_META_DATA, mCurrentUserId);
274 for (ResolveInfo rInfo : rInfos) {
275 String packageName = rInfo.serviceInfo.packageName;
276
277 // Check that the signature is in the list of supported sigs. If it's not in
278 // this list the standard provider binding logic won't bind to it.
279 try {
280 PackageInfo pInfo;
281 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
282 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
283 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
284 ", but has wrong signature, ignoring");
285 continue;
286 }
287 } catch (NameNotFoundException e) {
288 Log.e(TAG, "missing package: " + packageName);
289 continue;
290 }
291
292 // Get the version info
293 if (rInfo.serviceInfo.metaData == null) {
294 Log.w(TAG, "Found fused provider without metadata: " + packageName);
295 continue;
296 }
297
298 int version = rInfo.serviceInfo.metaData.getInt(
299 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
300 if (version == 0) {
301 // This should be the fallback fused location provider.
302
303 // Make sure it's in the system partition.
304 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
305 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
306 continue;
307 }
308
309 // Check that the fallback is signed the same as the OS
310 // as a proxy for coreApp="true"
311 if (pm.checkSignatures(systemPackageName, packageName)
312 != PackageManager.SIGNATURE_MATCH) {
313 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
314 + packageName);
315 continue;
316 }
317
318 // Found a valid fallback.
319 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
320 return;
321 } else {
322 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
323 }
324 }
325
326 throw new IllegalStateException("Unable to find a fused location provider that is in the "
327 + "system partition with version 0 and signed with the platform certificate. "
328 + "Such a package is needed to provide a default fused location provider in the "
329 + "event that no other fused location provider has been installed or is currently "
330 + "available. For example, coreOnly boot mode when decrypting the data "
331 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
332 }
333
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700334 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700335 // create a passive location provider, which is always enabled
336 PassiveProvider passiveProvider = new PassiveProvider(this);
337 addProviderLocked(passiveProvider);
338 mEnabledProviders.add(passiveProvider.getName());
339 mPassiveProvider = passiveProvider;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700340 // Create a gps location provider
341 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
342 mLocationHandler.getLooper());
Victoria Lease5c24fd02012-10-01 11:00:50 -0700343
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700344 if (GpsLocationProvider.isSupported()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700345 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
346 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
347 addProviderLocked(gpsProvider);
348 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
349 }
350
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700351 /*
352 Load package name(s) containing location provider support.
353 These packages can contain services implementing location providers:
354 Geocoder Provider, Network Location Provider, and
355 Fused Location Provider. They will each be searched for
356 service components implementing these providers.
357 The location framework also has support for installation
358 of new location providers at run-time. The new package does not
359 have to be explicitly listed here, however it must have a signature
360 that matches the signature of at least one package on this list.
361 */
362 Resources resources = mContext.getResources();
363 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500364 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700365 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500366 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
367 Arrays.toString(pkgs));
368 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
369
370 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700371
372 // bind to network provider
373 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
374 mContext,
375 LocationManager.NETWORK_PROVIDER,
376 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700377 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
378 com.android.internal.R.string.config_networkLocationProviderPackageName,
379 com.android.internal.R.array.config_locationProviderPackageNames,
380 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700381 if (networkProvider != null) {
382 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
383 mProxyProviders.add(networkProvider);
384 addProviderLocked(networkProvider);
385 } else {
386 Slog.w(TAG, "no network location provider found");
387 }
388
389 // bind to fused provider
390 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
391 mContext,
392 LocationManager.FUSED_PROVIDER,
393 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700394 com.android.internal.R.bool.config_enableFusedLocationOverlay,
395 com.android.internal.R.string.config_fusedLocationProviderPackageName,
396 com.android.internal.R.array.config_locationProviderPackageNames,
397 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700398 if (fusedLocationProvider != null) {
399 addProviderLocked(fusedLocationProvider);
400 mProxyProviders.add(fusedLocationProvider);
401 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700402 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700403 } else {
404 Slog.e(TAG, "no fused location provider found",
405 new IllegalStateException("Location service needs a fused location provider"));
406 }
407
408 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700409 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
410 com.android.internal.R.bool.config_enableGeocoderOverlay,
411 com.android.internal.R.string.config_geocoderProviderPackageName,
412 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800413 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700414 if (mGeocodeProvider == null) {
415 Slog.e(TAG, "no geocoder provider found");
416 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700417
418 // bind to geofence provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700419 GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
420 com.android.internal.R.bool.config_enableGeofenceOverlay,
421 com.android.internal.R.string.config_geofenceProviderPackageName,
422 com.android.internal.R.array.config_locationProviderPackageNames,
423 mLocationHandler,
424 gpsProvider.getGpsGeofenceProxy());
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700425 if (provider == null) {
426 Slog.e(TAG, "no geofence provider found");
427 }
428
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700429 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700432 * Called when the device's active user changes.
433 * @param userId the new active user's UserId
434 */
435 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700436 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800437 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700438 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700439 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700440 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700441 for (LocationProviderInterface p : mProviders) {
442 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700443 }
Victoria Lease38389b62012-09-30 11:44:22 -0700444 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700445 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700446 }
447 }
448
449 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
451 * location updates.
452 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700453 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700454 final int mUid; // uid of receiver
455 final int mPid; // pid of receiver
456 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700457 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 final ILocationListener mListener;
460 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700462
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400463 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700464
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700465 boolean mOpMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700466 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700467 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700469 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
470 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700473 if (listener != null) {
474 mKey = listener.asBinder();
475 } else {
476 mKey = intent;
477 }
Victoria Lease37425c32012-10-16 16:08:48 -0700478 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700479 mUid = uid;
480 mPid = pid;
481 mPackageName = packageName;
Victoria Lease0aa28602013-05-29 15:28:26 -0700482
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700483 updateMonitoring(true);
484
Victoria Lease0aa28602013-05-29 15:28:26 -0700485 // construct/configure wakelock
486 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
487 mWakeLock.setWorkSource(new WorkSource(mUid, mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 }
489
490 @Override
491 public boolean equals(Object otherObj) {
492 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700493 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 }
495 return false;
496 }
497
498 @Override
499 public int hashCode() {
500 return mKey.hashCode();
501 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 @Override
504 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700505 StringBuilder s = new StringBuilder();
506 s.append("Reciever[");
507 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700509 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700511 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700513 for (String p : mUpdateRecords.keySet()) {
514 s.append(" ").append(mUpdateRecords.get(p).toString());
515 }
516 s.append("]");
517 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 }
519
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700520 public void updateMonitoring(boolean allow) {
521 if (!mOpMonitoring) {
522 if (allow) {
523 mOpMonitoring = mAppOps.startOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
524 mUid, mPackageName) == AppOpsManager.MODE_ALLOWED;
525 }
526 } else {
527 if (!allow || mAppOps.checkOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
528 mUid, mPackageName) != AppOpsManager.MODE_ALLOWED) {
529 mAppOps.finishOp(AppOpsManager.OP_MONITOR_LOCATION, mUid, mPackageName);
530 mOpMonitoring = false;
531 }
532 }
533 }
534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 public boolean isListener() {
536 return mListener != null;
537 }
538
539 public boolean isPendingIntent() {
540 return mPendingIntent != null;
541 }
542
543 public ILocationListener getListener() {
544 if (mListener != null) {
545 return mListener;
546 }
547 throw new IllegalStateException("Request for non-existent listener");
548 }
549
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
551 if (mListener != null) {
552 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700553 synchronized (this) {
554 // synchronize to ensure incrementPendingBroadcastsLocked()
555 // is called before decrementPendingBroadcasts()
556 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700557 // call this after broadcasting so we do not increment
558 // if we throw an exeption.
559 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 } catch (RemoteException e) {
562 return false;
563 }
564 } else {
565 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800566 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
568 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700569 synchronized (this) {
570 // synchronize to ensure incrementPendingBroadcastsLocked()
571 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700572 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700573 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700574 // call this after broadcasting so we do not increment
575 // if we throw an exeption.
576 incrementPendingBroadcastsLocked();
577 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 } catch (PendingIntent.CanceledException e) {
579 return false;
580 }
581 }
582 return true;
583 }
584
585 public boolean callLocationChangedLocked(Location location) {
586 if (mListener != null) {
587 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700588 synchronized (this) {
589 // synchronize to ensure incrementPendingBroadcastsLocked()
590 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800591 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700592 // call this after broadcasting so we do not increment
593 // if we throw an exeption.
594 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 } catch (RemoteException e) {
597 return false;
598 }
599 } else {
600 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800601 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700603 synchronized (this) {
604 // synchronize to ensure incrementPendingBroadcastsLocked()
605 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700606 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700607 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700608 // call this after broadcasting so we do not increment
609 // if we throw an exeption.
610 incrementPendingBroadcastsLocked();
611 }
612 } catch (PendingIntent.CanceledException e) {
613 return false;
614 }
615 }
616 return true;
617 }
618
619 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
620 if (mListener != null) {
621 try {
622 synchronized (this) {
623 // synchronize to ensure incrementPendingBroadcastsLocked()
624 // is called before decrementPendingBroadcasts()
625 if (enabled) {
626 mListener.onProviderEnabled(provider);
627 } else {
628 mListener.onProviderDisabled(provider);
629 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700630 // call this after broadcasting so we do not increment
631 // if we throw an exeption.
632 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700633 }
634 } catch (RemoteException e) {
635 return false;
636 }
637 } else {
638 Intent providerIntent = new Intent();
639 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
640 try {
641 synchronized (this) {
642 // synchronize to ensure incrementPendingBroadcastsLocked()
643 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700644 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700645 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700646 // call this after broadcasting so we do not increment
647 // if we throw an exeption.
648 incrementPendingBroadcastsLocked();
649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 } catch (PendingIntent.CanceledException e) {
651 return false;
652 }
653 }
654 return true;
655 }
656
Nick Pellyf1be6862012-05-15 10:53:42 -0700657 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700659 if (D) Log.d(TAG, "Location listener died");
660
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400661 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 removeUpdatesLocked(this);
663 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700664 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700665 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700666 }
667 }
668
Nick Pellye0fd6932012-07-11 10:26:13 -0700669 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700670 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
671 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400672 synchronized (this) {
673 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700674 }
675 }
676
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400677 // this must be called while synchronized by caller in a synchronized block
678 // containing the sending of the broadcaset
679 private void incrementPendingBroadcastsLocked() {
680 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700681 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400682 }
683 }
684
685 private void decrementPendingBroadcastsLocked() {
686 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700687 if (mWakeLock.isHeld()) {
688 mWakeLock.release();
689 }
690 }
691 }
692
693 public void clearPendingBroadcastsLocked() {
694 if (mPendingBroadcasts > 0) {
695 mPendingBroadcasts = 0;
696 if (mWakeLock.isHeld()) {
697 mWakeLock.release();
698 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700699 }
700 }
701 }
702
Nick Pellye0fd6932012-07-11 10:26:13 -0700703 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700704 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700705 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400706 //the receiver list if it is not found. If it is not found then the
707 //LocationListener was removed when it had a pending broadcast and should
708 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700709 synchronized (mLock) {
710 IBinder binder = listener.asBinder();
711 Receiver receiver = mReceivers.get(binder);
712 if (receiver != null) {
713 synchronized (receiver) {
714 // so wakelock calls will succeed
715 long identity = Binder.clearCallingIdentity();
716 receiver.decrementPendingBroadcastsLocked();
717 Binder.restoreCallingIdentity(identity);
718 }
719 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 }
721 }
722
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700723 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400724 mProviders.add(provider);
725 mProvidersByName.put(provider.getName(), provider);
726 }
727
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700728 private void removeProviderLocked(LocationProviderInterface provider) {
729 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400730 mProviders.remove(provider);
731 mProvidersByName.remove(provider.getName());
732 }
733
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800734 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800735 * Returns "true" if access to the specified location provider is allowed by the current
736 * user's settings. Access to all location providers is forbidden to non-location-provider
737 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800738 *
739 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800740 * @return
741 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800742 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 if (mEnabledProviders.contains(provider)) {
744 return true;
745 }
746 if (mDisabledProviders.contains(provider)) {
747 return false;
748 }
749 // Use system settings
750 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751
Victoria Leaseb711d572012-10-02 13:14:11 -0700752 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 }
754
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700755 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800756 * Returns "true" if access to the specified location provider is allowed by the specified
757 * user's settings. Access to all location providers is forbidden to non-location-provider
758 * processes belonging to background users.
759 *
760 * @param provider the name of the location provider
761 * @param uid the requestor's UID
762 * @return
763 */
764 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
765 if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) {
766 return false;
767 }
768 return isAllowedByCurrentUserSettingsLocked(provider);
769 }
770
771 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700772 * Returns the permission string associated with the specified resolution level.
773 *
774 * @param resolutionLevel the resolution level
775 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700776 */
Victoria Lease37425c32012-10-16 16:08:48 -0700777 private String getResolutionPermission(int resolutionLevel) {
778 switch (resolutionLevel) {
779 case RESOLUTION_LEVEL_FINE:
780 return android.Manifest.permission.ACCESS_FINE_LOCATION;
781 case RESOLUTION_LEVEL_COARSE:
782 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
783 default:
784 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700786 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700787
Victoria Leaseda479c52012-10-15 15:24:16 -0700788 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700789 * Returns the resolution level allowed to the given PID/UID pair.
790 *
791 * @param pid the PID
792 * @param uid the UID
793 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700794 */
Victoria Lease37425c32012-10-16 16:08:48 -0700795 private int getAllowedResolutionLevel(int pid, int uid) {
796 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
797 pid, uid) == PackageManager.PERMISSION_GRANTED) {
798 return RESOLUTION_LEVEL_FINE;
799 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
800 pid, uid) == PackageManager.PERMISSION_GRANTED) {
801 return RESOLUTION_LEVEL_COARSE;
802 } else {
803 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700804 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700805 }
806
807 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700808 * Returns the resolution level allowed to the caller
809 *
810 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700811 */
Victoria Lease37425c32012-10-16 16:08:48 -0700812 private int getCallerAllowedResolutionLevel() {
813 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
814 }
815
816 /**
817 * Throw SecurityException if specified resolution level is insufficient to use geofences.
818 *
819 * @param allowedResolutionLevel resolution level allowed to caller
820 */
821 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
822 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700823 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
824 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 }
826
Victoria Lease37425c32012-10-16 16:08:48 -0700827 /**
828 * Return the minimum resolution level required to use the specified location provider.
829 *
830 * @param provider the name of the location provider
831 * @return minimum resolution level required for provider
832 */
833 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700834 if (LocationManager.GPS_PROVIDER.equals(provider) ||
835 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
836 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700837 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700838 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
839 LocationManager.FUSED_PROVIDER.equals(provider)) {
840 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700841 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700842 } else {
843 // mock providers
844 LocationProviderInterface lp = mMockProviders.get(provider);
845 if (lp != null) {
846 ProviderProperties properties = lp.getProperties();
847 if (properties != null) {
848 if (properties.mRequiresSatellite) {
849 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700850 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700851 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
852 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700853 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700854 }
855 }
856 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700857 }
Victoria Lease37425c32012-10-16 16:08:48 -0700858 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700859 }
860
Victoria Lease37425c32012-10-16 16:08:48 -0700861 /**
862 * Throw SecurityException if specified resolution level is insufficient to use the named
863 * location provider.
864 *
865 * @param allowedResolutionLevel resolution level allowed to caller
866 * @param providerName the name of the location provider
867 */
868 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
869 String providerName) {
870 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
871 if (allowedResolutionLevel < requiredResolutionLevel) {
872 switch (requiredResolutionLevel) {
873 case RESOLUTION_LEVEL_FINE:
874 throw new SecurityException("\"" + providerName + "\" location provider " +
875 "requires ACCESS_FINE_LOCATION permission.");
876 case RESOLUTION_LEVEL_COARSE:
877 throw new SecurityException("\"" + providerName + "\" location provider " +
878 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
879 default:
880 throw new SecurityException("Insufficient permission for \"" + providerName +
881 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700882 }
883 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700884 }
885
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800886 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800887 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
888 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800889 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800890 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800891 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800892 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800893 }
894 return -1;
895 }
896
897 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
898 int op = resolutionLevelToOp(allowedResolutionLevel);
899 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800900 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
901 return false;
902 }
903 }
904 return true;
905 }
906
907 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800908 int op = resolutionLevelToOp(allowedResolutionLevel);
909 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800910 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
911 return false;
912 }
913 }
914 return true;
915 }
916
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700917 /**
918 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700919 * fused, also including ones that are not permitted to
920 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700921 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700922 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700924 ArrayList<String> out;
925 synchronized (mLock) {
926 out = new ArrayList<String>(mProviders.size());
927 for (LocationProviderInterface provider : mProviders) {
928 String name = provider.getName();
929 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700930 continue;
931 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 out.add(name);
933 }
934 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700935
936 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 return out;
938 }
939
Mike Lockwood03ca2162010-04-01 08:10:09 -0700940 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700941 * Return all providers by name, that match criteria and are optionally
942 * enabled.
943 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700944 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700945 @Override
946 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700947 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700948 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800949 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -0700950 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700951 try {
952 synchronized (mLock) {
953 out = new ArrayList<String>(mProviders.size());
954 for (LocationProviderInterface provider : mProviders) {
955 String name = provider.getName();
956 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700957 continue;
958 }
Victoria Lease37425c32012-10-16 16:08:48 -0700959 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -0800960 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700961 continue;
962 }
963 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
964 name, provider.getProperties(), criteria)) {
965 continue;
966 }
967 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700968 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700969 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700970 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700971 } finally {
972 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700973 }
974
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700975 if (D) Log.d(TAG, "getProviders()=" + out);
976 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700977 }
978
979 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700980 * Return the name of the best provider given a Criteria object.
981 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700982 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700983 * has been deprecated as well. So this method now uses
984 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700985 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700986 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700987 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700988 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700989
990 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700991 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700992 result = pickBest(providers);
993 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
994 return result;
995 }
996 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700997 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700998 result = pickBest(providers);
999 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1000 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001001 }
1002
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001003 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001004 return null;
1005 }
1006
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001007 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001008 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001009 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001010 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1011 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001012 } else {
1013 return providers.get(0);
1014 }
1015 }
1016
Nick Pellye0fd6932012-07-11 10:26:13 -07001017 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001018 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1019 LocationProviderInterface p = mProvidersByName.get(provider);
1020 if (p == null) {
1021 throw new IllegalArgumentException("provider=" + provider);
1022 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001023
1024 boolean result = LocationProvider.propertiesMeetCriteria(
1025 p.getName(), p.getProperties(), criteria);
1026 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1027 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001028 }
1029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001031 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001032 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001033 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 boolean isEnabled = p.isEnabled();
1035 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001036 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001038 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001039 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001041 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001042 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001044 }
1045 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001046 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1047 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 }
1049 }
1050
Victoria Leaseb711d572012-10-02 13:14:11 -07001051 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 int listeners = 0;
1053
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001054 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001055 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056
1057 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1060 if (records != null) {
1061 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001062 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -07001064 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001065 // Sends a notification message to the receiver
1066 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1067 if (deadReceivers == null) {
1068 deadReceivers = new ArrayList<Receiver>();
1069 }
1070 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001072 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 }
1075 }
1076
1077 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001078 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 removeUpdatesLocked(deadReceivers.get(i));
1080 }
1081 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 if (enabled) {
1084 p.enable();
1085 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001086 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 }
1088 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 }
1092
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001093 private void applyRequirementsLocked(String provider) {
1094 LocationProviderInterface p = mProvidersByName.get(provider);
1095 if (p == null) return;
1096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001098 WorkSource worksource = new WorkSource();
1099 ProviderRequest providerRequest = new ProviderRequest();
1100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001102 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001103 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001104 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1105 record.mReceiver.mAllowedResolutionLevel)) {
1106 LocationRequest locationRequest = record.mRequest;
1107 providerRequest.locationRequests.add(locationRequest);
1108 if (locationRequest.getInterval() < providerRequest.interval) {
1109 providerRequest.reportLocation = true;
1110 providerRequest.interval = locationRequest.getInterval();
1111 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001112 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001113 }
1114 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001115
1116 if (providerRequest.reportLocation) {
1117 // calculate who to blame for power
1118 // This is somewhat arbitrary. We pick a threshold interval
1119 // that is slightly higher that the minimum interval, and
1120 // spread the blame across all applications with a request
1121 // under that threshold.
1122 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1123 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001124 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001125 LocationRequest locationRequest = record.mRequest;
1126 if (locationRequest.getInterval() <= thresholdInterval) {
Dianne Hackborn002a54e2013-01-10 17:34:55 -08001127 worksource.add(record.mReceiver.mUid, record.mReceiver.mPackageName);
Victoria Leaseb711d572012-10-02 13:14:11 -07001128 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001129 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001130 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 }
1132 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001133
1134 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1135 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 }
1137
1138 private class UpdateRecord {
1139 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001140 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001142 Location mLastFixBroadcast;
1143 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144
1145 /**
1146 * Note: must be constructed with lock held.
1147 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001148 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001150 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152
1153 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1154 if (records == null) {
1155 records = new ArrayList<UpdateRecord>();
1156 mRecordsByProvider.put(provider, records);
1157 }
1158 if (!records.contains(this)) {
1159 records.add(this);
1160 }
1161 }
1162
1163 /**
1164 * Method to be called when a record will no longer be used. Calling this multiple times
1165 * must have the same effect as calling it once.
1166 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001167 void disposeLocked(boolean removeReceiver) {
1168 // remove from mRecordsByProvider
1169 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1170 if (globalRecords != null) {
1171 globalRecords.remove(this);
1172 }
1173
1174 if (!removeReceiver) return; // the caller will handle the rest
1175
1176 // remove from Receiver#mUpdateRecords
1177 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1178 if (receiverRecords != null) {
1179 receiverRecords.remove(this.mProvider);
1180
1181 // and also remove the Receiver if it has no more update records
1182 if (removeReceiver && receiverRecords.size() == 0) {
1183 removeUpdatesLocked(mReceiver);
1184 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001185 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 }
1187
1188 @Override
1189 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001190 StringBuilder s = new StringBuilder();
1191 s.append("UpdateRecord[");
1192 s.append(mProvider);
1193 s.append(' ').append(mReceiver.mPackageName).append('(');
1194 s.append(mReceiver.mUid).append(')');
1195 s.append(' ').append(mRequest);
1196 s.append(']');
1197 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 }
1200
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001201 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
1202 String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001203 IBinder binder = listener.asBinder();
1204 Receiver receiver = mReceivers.get(binder);
1205 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001206 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001207 mReceivers.put(binder, receiver);
1208
1209 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001210 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001211 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001212 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001213 return null;
1214 }
1215 }
1216 return receiver;
1217 }
1218
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001219 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001220 Receiver receiver = mReceivers.get(intent);
1221 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001223 mReceivers.put(intent, receiver);
1224 }
1225 return receiver;
1226 }
1227
Victoria Lease37425c32012-10-16 16:08:48 -07001228 /**
1229 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1230 * and consistency requirements.
1231 *
1232 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001233 * @return a version of request that meets the given resolution and consistency requirements
1234 * @hide
1235 */
1236 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1237 LocationRequest sanitizedRequest = new LocationRequest(request);
1238 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1239 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001240 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001241 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001242 break;
1243 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001244 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001245 break;
1246 }
1247 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001248 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1249 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001250 }
Victoria Lease37425c32012-10-16 16:08:48 -07001251 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1252 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001253 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001254 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001255 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001256 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001257 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001258 }
Victoria Lease37425c32012-10-16 16:08:48 -07001259 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001260 }
1261
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001262 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001263 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001264 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001265 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001266 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001267 String[] packages = mPackageManager.getPackagesForUid(uid);
1268 if (packages == null) {
1269 throw new SecurityException("invalid UID " + uid);
1270 }
1271 for (String pkg : packages) {
1272 if (packageName.equals(pkg)) return;
1273 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001274 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001275 }
1276
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001277 private void checkPendingIntent(PendingIntent intent) {
1278 if (intent == null) {
1279 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001280 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001281 }
1282
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001283 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 int pid, int uid, String packageName) {
1285 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001286 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001287 } else if (intent != null && listener != null) {
1288 throw new IllegalArgumentException("cannot register both listener and intent");
1289 } else if (intent != null) {
1290 checkPendingIntent(intent);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001291 return getReceiverLocked(intent, pid, uid, packageName);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001292 } else {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001293 return getReceiverLocked(listener, pid, uid, packageName);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001294 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001295 }
1296
Nick Pellye0fd6932012-07-11 10:26:13 -07001297 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001298 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1299 PendingIntent intent, String packageName) {
1300 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1301 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001302 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1303 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1304 request.getProvider());
1305 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001307 final int pid = Binder.getCallingPid();
1308 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001309 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 long identity = Binder.clearCallingIdentity();
1311 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001312 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1313 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001314 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001315
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001316 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001317 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
1318 packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001319 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 } finally {
1322 Binder.restoreCallingIdentity(identity);
1323 }
1324 }
1325
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001326 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1327 int pid, int uid, String packageName) {
1328 // Figure out the provider. Either its explicitly request (legacy use cases), or
1329 // use the fused provider
1330 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1331 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001332 if (name == null) {
1333 throw new IllegalArgumentException("provider name must not be null");
1334 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001335
1336 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1337 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001338 LocationProviderInterface provider = mProvidersByName.get(name);
1339 if (provider == null) {
1340 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1341 }
1342
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001343 UpdateRecord record = new UpdateRecord(name, request, receiver);
1344 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1345 if (oldRecord != null) {
1346 oldRecord.disposeLocked(false);
1347 }
1348
Victoria Lease09eeaec2013-02-05 11:34:13 -08001349 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001350 if (isProviderEnabled) {
1351 applyRequirementsLocked(name);
1352 } else {
1353 // Notify the listener that updates are currently disabled
1354 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 }
1356 }
1357
Nick Pellye0fd6932012-07-11 10:26:13 -07001358 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001359 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1360 String packageName) {
1361 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001362
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001363 final int pid = Binder.getCallingPid();
1364 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001365
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001366 synchronized (mLock) {
1367 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, packageName);
1368
1369 // providers may use public location API's, need to clear identity
1370 long identity = Binder.clearCallingIdentity();
1371 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001372 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001373 } finally {
1374 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001376 }
1377 }
1378
1379 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001380 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001381
1382 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1383 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1384 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001385 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001386 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 }
1388
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001389 receiver.updateMonitoring(false);
1390
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001391 // Record which providers were associated with this listener
1392 HashSet<String> providers = new HashSet<String>();
1393 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1394 if (oldRecords != null) {
1395 // Call dispose() on the obsolete update records.
1396 for (UpdateRecord record : oldRecords.values()) {
1397 record.disposeLocked(false);
1398 }
1399 // Accumulate providers
1400 providers.addAll(oldRecords.keySet());
1401 }
1402
1403 // update provider
1404 for (String provider : providers) {
1405 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001406 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001407 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 }
1409
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001410 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 }
1412 }
1413
Dianne Hackbornc2293022013-02-06 23:14:49 -08001414 private void applyAllProviderRequirementsLocked() {
1415 for (LocationProviderInterface p : mProviders) {
1416 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001417 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001418 continue;
1419 }
1420
1421 applyRequirementsLocked(p.getName());
1422 }
1423 }
1424
Nick Pellye0fd6932012-07-11 10:26:13 -07001425 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001426 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001427 if (D) Log.d(TAG, "getLastLocation: " + request);
1428 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001429 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001430 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001431 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1432 request.getProvider());
1433 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001434
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001435 final int uid = Binder.getCallingUid();
1436 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001437 try {
1438 if (mBlacklist.isBlacklisted(packageName)) {
1439 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1440 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001441 return null;
1442 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001443
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001444 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1445 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1446 packageName);
1447 return null;
1448 }
1449
Victoria Leaseb711d572012-10-02 13:14:11 -07001450 synchronized (mLock) {
1451 // Figure out the provider. Either its explicitly request (deprecated API's),
1452 // or use the fused provider
1453 String name = request.getProvider();
1454 if (name == null) name = LocationManager.FUSED_PROVIDER;
1455 LocationProviderInterface provider = mProvidersByName.get(name);
1456 if (provider == null) return null;
1457
Victoria Lease09eeaec2013-02-05 11:34:13 -08001458 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001459
David Christie1b9b7b12013-04-15 15:31:11 -07001460 Location location;
1461 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1462 // Make sure that an app with coarse permissions can't get frequent location
1463 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1464 location = mLastLocationCoarseInterval.get(name);
1465 } else {
1466 location = mLastLocation.get(name);
1467 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001468 if (location == null) {
1469 return null;
1470 }
Victoria Lease37425c32012-10-16 16:08:48 -07001471 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001472 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1473 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001474 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001475 }
Victoria Lease37425c32012-10-16 16:08:48 -07001476 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001477 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001478 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001479 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001480 return null;
1481 } finally {
1482 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001483 }
1484 }
1485
1486 @Override
1487 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1488 String packageName) {
1489 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001490 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1491 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001492 checkPendingIntent(intent);
1493 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001494 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1495 request.getProvider());
1496 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001497
Victoria Lease37425c32012-10-16 16:08:48 -07001498 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001499
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001500 // geo-fence manager uses the public location API, need to clear identity
1501 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001502 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1503 // temporary measure until geofences work for secondary users
1504 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1505 return;
1506 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001507 long identity = Binder.clearCallingIdentity();
1508 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001509 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1510 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001511 } finally {
1512 Binder.restoreCallingIdentity(identity);
1513 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001514 }
1515
1516 @Override
1517 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001518 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001519 checkPendingIntent(intent);
1520 checkPackageName(packageName);
1521
1522 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1523
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001524 // geo-fence manager uses the public location API, need to clear identity
1525 long identity = Binder.clearCallingIdentity();
1526 try {
1527 mGeofenceManager.removeFence(geofence, intent);
1528 } finally {
1529 Binder.restoreCallingIdentity(identity);
1530 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001531 }
1532
1533
1534 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001535 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001536 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 return false;
1538 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001539 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1540 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001541 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001543 final int uid = Binder.getCallingUid();
1544 final long ident = Binder.clearCallingIdentity();
1545 try {
Victoria Lease3d5173d2013-02-05 16:07:32 -08001546 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001547 return false;
1548 }
1549 } finally {
1550 Binder.restoreCallingIdentity(ident);
1551 }
1552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001554 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001556 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 return false;
1558 }
1559 return true;
1560 }
1561
Nick Pellye0fd6932012-07-11 10:26:13 -07001562 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001564 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001565 try {
1566 mGpsStatusProvider.removeGpsStatusListener(listener);
1567 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001568 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001569 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 }
1571 }
1572
Nick Pellye0fd6932012-07-11 10:26:13 -07001573 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001575 if (provider == null) {
1576 // throw NullPointerException to remain compatible with previous implementation
1577 throw new NullPointerException();
1578 }
Victoria Lease37425c32012-10-16 16:08:48 -07001579 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1580 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001581
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001583 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 != PackageManager.PERMISSION_GRANTED)) {
1585 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1586 }
1587
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001588 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001589 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001590 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001591
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001592 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 }
1594 }
1595
Nick Pellye0fd6932012-07-11 10:26:13 -07001596 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001597 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001598 if (Binder.getCallingUid() != Process.myUid()) {
1599 throw new SecurityException(
1600 "calling sendNiResponse from outside of the system is not allowed");
1601 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001602 try {
1603 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001604 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001605 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001606 return false;
1607 }
1608 }
1609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001611 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001612 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 * accessed by the caller
1614 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001615 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001616 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001617 if (mProvidersByName.get(provider) == null) {
1618 return null;
1619 }
1620
Victoria Lease37425c32012-10-16 16:08:48 -07001621 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1622 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001624 LocationProviderInterface p;
1625 synchronized (mLock) {
1626 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 }
1628
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001629 if (p == null) return null;
1630 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 }
1632
Nick Pellye0fd6932012-07-11 10:26:13 -07001633 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001635 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1636 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001637 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1638
Victoria Lease09eeaec2013-02-05 11:34:13 -08001639 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001640 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001641 try {
1642 synchronized (mLock) {
1643 LocationProviderInterface p = mProvidersByName.get(provider);
1644 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001645
Victoria Lease09eeaec2013-02-05 11:34:13 -08001646 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001647 }
1648 } finally {
1649 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001650 }
1651 }
1652
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001653 /**
1654 * Returns "true" if the UID belongs to a bound location provider.
1655 *
1656 * @param uid the uid
1657 * @return true if uid belongs to a bound location provider
1658 */
1659 private boolean isUidALocationProvider(int uid) {
1660 if (uid == Process.SYSTEM_UID) {
1661 return true;
1662 }
1663 if (mGeocodeProvider != null) {
1664 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1665 }
1666 for (LocationProviderProxy proxy : mProxyProviders) {
1667 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
1668 }
1669 return false;
1670 }
1671
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001672 private void checkCallerIsProvider() {
1673 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1674 == PackageManager.PERMISSION_GRANTED) {
1675 return;
1676 }
1677
1678 // Previously we only used the INSTALL_LOCATION_PROVIDER
1679 // check. But that is system or signature
1680 // protection level which is not flexible enough for
1681 // providers installed oustide the system image. So
1682 // also allow providers with a UID matching the
1683 // currently bound package name
1684
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001685 if (isUidALocationProvider(Binder.getCallingUid())) {
1686 return;
1687 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001688
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001689 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1690 "or UID of a currently bound location provider");
1691 }
1692
1693 private boolean doesPackageHaveUid(int uid, String packageName) {
1694 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 return false;
1696 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001697 try {
1698 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1699 if (appInfo.uid != uid) {
1700 return false;
1701 }
1702 } catch (NameNotFoundException e) {
1703 return false;
1704 }
1705 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 }
1707
Nick Pellye0fd6932012-07-11 10:26:13 -07001708 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001709 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001710 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001711
Nick Pelly2eeeec22012-07-18 13:13:37 -07001712 if (!location.isComplete()) {
1713 Log.w(TAG, "Dropping incomplete location: " + location);
1714 return;
1715 }
1716
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001717 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1718 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001719 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001720 mLocationHandler.sendMessageAtFrontOfQueue(m);
1721 }
1722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723
Laurent Tu75defb62012-11-01 16:21:52 -07001724 private static boolean shouldBroadcastSafe(
1725 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 // Always broadcast the first update
1727 if (lastLoc == null) {
1728 return true;
1729 }
1730
Nick Pellyf1be6862012-05-15 10:53:42 -07001731 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001732 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07001733 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
1734 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001735 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 return false;
1737 }
1738
1739 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001740 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 if (minDistance > 0.0) {
1742 if (loc.distanceTo(lastLoc) <= minDistance) {
1743 return false;
1744 }
1745 }
1746
Laurent Tu75defb62012-11-01 16:21:52 -07001747 // Check whether sufficient number of udpates is left
1748 if (record.mRequest.getNumUpdates() <= 0) {
1749 return false;
1750 }
1751
1752 // Check whether the expiry date has passed
1753 if (record.mRequest.getExpireAt() < now) {
1754 return false;
1755 }
1756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 return true;
1758 }
1759
Mike Lockwooda4903f22010-02-17 06:42:23 -05001760 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001761 if (D) Log.d(TAG, "incoming location: " + location);
1762
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001763 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001764 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765
Laurent Tu60ec50a2012-10-04 17:00:10 -07001766 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001767 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001768 if (p == null) return;
1769
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001770 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001771 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1772 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001773 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001774 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001775 lastLocation = new Location(provider);
1776 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001777 } else {
1778 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1779 if (noGPSLocation == null && lastNoGPSLocation != null) {
1780 // New location has no no-GPS location: adopt last no-GPS location. This is set
1781 // directly into location because we do not want to notify COARSE clients.
1782 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1783 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001784 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001785 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786
David Christie1b9b7b12013-04-15 15:31:11 -07001787 // Update last known coarse interval location if enough time has passed.
1788 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
1789 if (lastLocationCoarseInterval == null) {
1790 lastLocationCoarseInterval = new Location(location);
1791 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
1792 }
1793 long timeDiffNanos = location.getElapsedRealtimeNanos()
1794 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
1795 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
1796 lastLocationCoarseInterval.set(location);
1797 }
1798 // Don't ever return a coarse location that is more recent than the allowed update
1799 // interval (i.e. don't allow an app to keep registering and unregistering for
1800 // location updates to overcome the minimum interval).
1801 noGPSLocation =
1802 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1803
Laurent Tu60ec50a2012-10-04 17:00:10 -07001804 // Skip if there are no UpdateRecords for this provider.
1805 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1806 if (records == null || records.size() == 0) return;
1807
Victoria Lease09016ab2012-09-16 12:33:15 -07001808 // Fetch coarse location
1809 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07001810 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001811 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1812 }
1813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 // Fetch latest status update time
1815 long newStatusUpdateTime = p.getStatusUpdateTime();
1816
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001817 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 Bundle extras = new Bundle();
1819 int status = p.getStatus(extras);
1820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001822 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001825 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001827 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001828
Victoria Lease269518e2012-10-29 08:25:39 -07001829 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Victoria Lease2f5b97c2013-05-07 14:22:02 -07001830 if (receiverUserId != mCurrentUserId && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001831 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001832 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001833 " (current user: " + mCurrentUserId + ", app: " +
1834 receiver.mPackageName + ")");
1835 }
1836 continue;
1837 }
1838
Nick Pelly4035f5a2012-08-17 14:43:49 -07001839 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1840 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1841 receiver.mPackageName);
1842 continue;
1843 }
1844
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001845 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
1846 receiver.mAllowedResolutionLevel)) {
1847 if (D) Log.d(TAG, "skipping loc update for no op app: " +
1848 receiver.mPackageName);
1849 continue;
1850 }
1851
Victoria Lease09016ab2012-09-16 12:33:15 -07001852 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001853 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1854 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001855 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001856 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001857 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001858 if (notifyLocation != null) {
1859 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001860 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001861 if (lastLoc == null) {
1862 lastLoc = new Location(notifyLocation);
1863 r.mLastFixBroadcast = lastLoc;
1864 } else {
1865 lastLoc.set(notifyLocation);
1866 }
1867 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1868 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1869 receiverDead = true;
1870 }
Laurent Tu75defb62012-11-01 16:21:52 -07001871 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 }
1873 }
1874
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001875 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001877 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001879 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001881 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001882 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001883 }
1884 }
1885
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001886 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001887 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001888 if (deadUpdateRecords == null) {
1889 deadUpdateRecords = new ArrayList<UpdateRecord>();
1890 }
1891 deadUpdateRecords.add(r);
1892 }
1893 // track dead receivers
1894 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001895 if (deadReceivers == null) {
1896 deadReceivers = new ArrayList<Receiver>();
1897 }
1898 if (!deadReceivers.contains(receiver)) {
1899 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001900 }
1901 }
1902 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001903
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001904 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001906 for (Receiver receiver : deadReceivers) {
1907 removeUpdatesLocked(receiver);
1908 }
1909 }
1910 if (deadUpdateRecords != null) {
1911 for (UpdateRecord r : deadUpdateRecords) {
1912 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 }
Victoria Lease8b38b292012-12-04 15:04:43 -08001914 applyRequirementsLocked(provider);
1915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 }
1917
1918 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001919 public LocationWorkerHandler(Looper looper) {
1920 super(looper, null, true);
1921 }
1922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 @Override
1924 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001925 switch (msg.what) {
1926 case MSG_LOCATION_CHANGED:
1927 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1928 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 }
1930 }
1931 }
1932
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001933 private boolean isMockProvider(String provider) {
1934 synchronized (mLock) {
1935 return mMockProviders.containsKey(provider);
1936 }
1937 }
1938
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001939 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001940 // create a working copy of the incoming Location so that the service can modify it without
1941 // disturbing the caller's copy
1942 Location myLocation = new Location(location);
1943 String provider = myLocation.getProvider();
1944
1945 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
1946 // bit if location did not come from a mock provider because passive/fused providers can
1947 // forward locations from mock providers, and should not grant them legitimacy in doing so.
1948 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
1949 myLocation.setIsFromMockProvider(true);
1950 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08001951
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001952 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001953 if (isAllowedByCurrentUserSettingsLocked(provider)) {
1954 if (!passive) {
1955 // notify passive provider of the new location
1956 mPassiveProvider.updateLocation(myLocation);
1957 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001958 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001961 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962
Mike Lockwoode97ae402010-09-29 15:23:46 -04001963 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1964 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001965 public void onPackageDisappeared(String packageName, int reason) {
1966 // remove all receivers associated with this package name
1967 synchronized (mLock) {
1968 ArrayList<Receiver> deadReceivers = null;
1969
1970 for (Receiver receiver : mReceivers.values()) {
1971 if (receiver.mPackageName.equals(packageName)) {
1972 if (deadReceivers == null) {
1973 deadReceivers = new ArrayList<Receiver>();
1974 }
1975 deadReceivers.add(receiver);
1976 }
1977 }
1978
1979 // perform removal outside of mReceivers loop
1980 if (deadReceivers != null) {
1981 for (Receiver receiver : deadReceivers) {
1982 removeUpdatesLocked(receiver);
1983 }
1984 }
1985 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001986 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001987 };
1988
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 // Geocoder
1990
Nick Pellye0fd6932012-07-11 10:26:13 -07001991 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001992 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001993 return mGeocodeProvider != null;
1994 }
1995
Nick Pellye0fd6932012-07-11 10:26:13 -07001996 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001998 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001999 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002000 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2001 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002003 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 }
2005
Mike Lockwooda55c3212009-04-15 11:10:11 -04002006
Nick Pellye0fd6932012-07-11 10:26:13 -07002007 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002009 double lowerLeftLatitude, double lowerLeftLongitude,
2010 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002011 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002012
2013 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002014 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2015 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2016 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002017 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002018 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 }
2020
2021 // Mock Providers
2022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002023 private void checkMockPermissionsSafe() {
2024 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2025 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2026 if (!allowMocks) {
2027 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2028 }
2029
2030 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2031 PackageManager.PERMISSION_GRANTED) {
2032 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07002033 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002034 }
2035
Nick Pellye0fd6932012-07-11 10:26:13 -07002036 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002037 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002038 checkMockPermissionsSafe();
2039
Mike Lockwooda4903f22010-02-17 06:42:23 -05002040 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2041 throw new IllegalArgumentException("Cannot mock the passive location provider");
2042 }
2043
Mike Lockwood86328a92009-10-23 08:38:25 -04002044 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002045 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002046 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002047 // remove the real provider if we are replacing GPS or network provider
2048 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002049 || LocationManager.NETWORK_PROVIDER.equals(name)
2050 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002051 LocationProviderInterface p = mProvidersByName.get(name);
2052 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002053 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002054 }
2055 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002056 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002057 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2058 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002059 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002060 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002061 mLastLocation.put(name, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002062 mLastLocationCoarseInterval.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002063 updateProvidersLocked();
2064 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002065 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 }
2067
Nick Pellye0fd6932012-07-11 10:26:13 -07002068 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 public void removeTestProvider(String provider) {
2070 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002071 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09002072 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002073 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002074 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2075 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002076 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002077 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002078
2079 // reinstate real provider if available
2080 LocationProviderInterface realProvider = mRealProviders.get(provider);
2081 if (realProvider != null) {
2082 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002083 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002084 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002085 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002086 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002087 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002088 }
2089 }
2090
Nick Pellye0fd6932012-07-11 10:26:13 -07002091 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002092 public void setTestProviderLocation(String provider, Location loc) {
2093 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002094 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002095 MockProvider mockProvider = mMockProviders.get(provider);
2096 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002097 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2098 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002099 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2100 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002101 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002102 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002103 }
2104 }
2105
Nick Pellye0fd6932012-07-11 10:26:13 -07002106 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 public void clearTestProviderLocation(String provider) {
2108 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002109 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002110 MockProvider mockProvider = mMockProviders.get(provider);
2111 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002112 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2113 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002114 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002115 }
2116 }
2117
Nick Pellye0fd6932012-07-11 10:26:13 -07002118 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 public void setTestProviderEnabled(String provider, boolean enabled) {
2120 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002121 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002122 MockProvider mockProvider = mMockProviders.get(provider);
2123 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002124 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2125 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002126 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002127 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002128 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002129 mEnabledProviders.add(provider);
2130 mDisabledProviders.remove(provider);
2131 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002132 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002133 mEnabledProviders.remove(provider);
2134 mDisabledProviders.add(provider);
2135 }
2136 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002137 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002138 }
2139 }
2140
Nick Pellye0fd6932012-07-11 10:26:13 -07002141 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002142 public void clearTestProviderEnabled(String provider) {
2143 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002144 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002145 MockProvider mockProvider = mMockProviders.get(provider);
2146 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2148 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002149 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002150 mEnabledProviders.remove(provider);
2151 mDisabledProviders.remove(provider);
2152 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002153 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002154 }
2155 }
2156
Nick Pellye0fd6932012-07-11 10:26:13 -07002157 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002158 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2159 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002160 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002161 MockProvider mockProvider = mMockProviders.get(provider);
2162 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2164 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002165 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002166 }
2167 }
2168
Nick Pellye0fd6932012-07-11 10:26:13 -07002169 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 public void clearTestProviderStatus(String provider) {
2171 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002172 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002173 MockProvider mockProvider = mMockProviders.get(provider);
2174 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002175 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2176 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002177 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002178 }
2179 }
2180
2181 private void log(String log) {
2182 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002183 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 }
2185 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002186
2187 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2189 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2190 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002191 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002192 + Binder.getCallingPid()
2193 + ", uid=" + Binder.getCallingUid());
2194 return;
2195 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002196
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002197 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002198 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002200 for (Receiver receiver : mReceivers.values()) {
2201 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002204 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2205 pw.println(" " + entry.getKey() + ":");
2206 for (UpdateRecord record : entry.getValue()) {
2207 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002208 }
2209 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002211 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2212 String provider = entry.getKey();
2213 Location location = entry.getValue();
2214 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002216
David Christie1b9b7b12013-04-15 15:31:11 -07002217 pw.println(" Last Known Locations Coarse Intervals:");
2218 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2219 String provider = entry.getKey();
2220 Location location = entry.getValue();
2221 pw.println(" " + provider + ": " + location);
2222 }
2223
Nick Pellye0fd6932012-07-11 10:26:13 -07002224 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002226 if (mEnabledProviders.size() > 0) {
2227 pw.println(" Enabled Providers:");
2228 for (String i : mEnabledProviders) {
2229 pw.println(" " + i);
2230 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 }
2233 if (mDisabledProviders.size() > 0) {
2234 pw.println(" Disabled Providers:");
2235 for (String i : mDisabledProviders) {
2236 pw.println(" " + i);
2237 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002238 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002239 pw.append(" ");
2240 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002241 if (mMockProviders.size() > 0) {
2242 pw.println(" Mock Providers:");
2243 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002244 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002245 }
2246 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002247
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002248 pw.append(" fudger: ");
2249 mLocationFudger.dump(fd, pw, args);
2250
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002251 if (args.length > 0 && "short".equals(args[0])) {
2252 return;
2253 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002254 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002255 pw.print(provider.getName() + " Internal State");
2256 if (provider instanceof LocationProviderProxy) {
2257 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2258 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002259 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002260 pw.println(":");
2261 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002262 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002263 }
2264 }
2265}