blob: 49746ffc624190a4c97d54c725e9e9a52daf3d3e [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;
destradaa1af4b022013-07-12 15:43:36 -070066import com.android.server.location.FlpHardwareProvider;
67import com.android.server.location.FusedProxy;
Mike Lockwood43e33f22010-03-26 10:41:48 -040068import com.android.server.location.GeocoderProxy;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -070069import com.android.server.location.GeofenceProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070070import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040071import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070072import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070073import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040074import com.android.server.location.LocationProviderInterface;
75import com.android.server.location.LocationProviderProxy;
76import com.android.server.location.MockProvider;
77import com.android.server.location.PassiveProvider;
78
79import java.io.FileDescriptor;
80import java.io.PrintWriter;
81import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070082import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040083import java.util.HashMap;
84import java.util.HashSet;
85import java.util.List;
86import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040087import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
89/**
90 * The service class that manages LocationProviders and issues location
91 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 */
Victoria Lease5cd731a2012-12-19 15:04:21 -080093public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -080095 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -070096
97 private static final String WAKELOCK_KEY = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098
Victoria Lease37425c32012-10-16 16:08:48 -070099 // Location resolution level: no location data whatsoever
100 private static final int RESOLUTION_LEVEL_NONE = 0;
101 // Location resolution level: coarse location data only
102 private static final int RESOLUTION_LEVEL_COARSE = 1;
103 // Location resolution level: fine location data
104 private static final int RESOLUTION_LEVEL_FINE = 2;
105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700107 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700109 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400110 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700111 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
112
113 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700114 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700115 private static final String FUSED_LOCATION_SERVICE_ACTION =
116 "com.android.location.service.FusedLocationProvider";
117
118 private static final int MSG_LOCATION_CHANGED = 1;
119
David Christie1b9b7b12013-04-15 15:31:11 -0700120 private static final long NANOS_PER_MILLI = 1000000L;
121
David Christie0b837452013-07-29 16:02:13 -0700122 // The maximum interval a location request can have and still be considered "high power".
123 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
124
Nick Pellyf1be6862012-05-15 10:53:42 -0700125 // Location Providers may sometimes deliver location updates
126 // slightly faster that requested - provide grace period so
127 // we don't unnecessarily filter events that are otherwise on
128 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700129 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700130
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700131 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
132
133 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800134 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700135
136 // used internally for synchronization
137 private final Object mLock = new Object();
138
Victoria Lease5cd731a2012-12-19 15:04:21 -0800139 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700140 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700141 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700142 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700143 private PowerManager mPowerManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700144 private GeocoderProxy mGeocodeProvider;
145 private IGpsStatusProvider mGpsStatusProvider;
146 private INetInitiatedListener mNetInitiatedListener;
147 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700148 private PassiveProvider mPassiveProvider; // track passive provider for special cases
149 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700150
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700151 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 // Set of providers that are explicitly enabled
153 private final Set<String> mEnabledProviders = new HashSet<String>();
154
155 // Set of providers that are explicitly disabled
156 private final Set<String> mDisabledProviders = new HashSet<String>();
157
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700158 // Mock (test) providers
159 private final HashMap<String, MockProvider> mMockProviders =
160 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400163 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700165 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500166 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // real providers, saved here when mocked out
170 private final HashMap<String, LocationProviderInterface> mRealProviders =
171 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700173 // mapping from provider name to provider
174 private final HashMap<String, LocationProviderInterface> mProvidersByName =
175 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 // mapping from provider name to all its UpdateRecords
178 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
179 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700180
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 // mapping from provider name to last known location
182 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
David Christie1b9b7b12013-04-15 15:31:11 -0700184 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
185 // locations stored here are not fudged for coarse permissions.
186 private final HashMap<String, Location> mLastLocationCoarseInterval =
187 new HashMap<String, Location>();
188
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700189 // all providers that operate over proxy, for authorizing incoming location
190 private final ArrayList<LocationProviderProxy> mProxyProviders =
191 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192
Victoria Lease38389b62012-09-30 11:44:22 -0700193 // current active user on the device - other users are denied location data
194 private int mCurrentUserId = UserHandle.USER_OWNER;
195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 public LocationManagerService(Context context) {
197 super();
198 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800199 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800200
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700201 if (D) Log.d(TAG, "Constructed");
202
203 // most startup is deferred until systemReady()
204 }
205
Svetoslav Ganova0027152013-06-25 14:59:53 -0700206 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700207 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800208 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700209
Victoria Lease5cd731a2012-12-19 15:04:21 -0800210 // fetch package manager
211 mPackageManager = mContext.getPackageManager();
212
Victoria Lease0aa28602013-05-29 15:28:26 -0700213 // fetch power manager
214 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800215
216 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700217 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800218
219 // prepare mLocationHandler's dependents
220 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
221 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
222 mBlacklist.init();
223 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
224
Dianne Hackbornc2293022013-02-06 23:14:49 -0800225 // Monitor for app ops mode changes.
226 AppOpsManager.Callback callback = new AppOpsManager.Callback() {
227 public void opChanged(int op, String packageName) {
228 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700229 for (Receiver receiver : mReceivers.values()) {
230 receiver.updateMonitoring(true);
231 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800232 applyAllProviderRequirementsLocked();
233 }
234 }
235 };
236 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
237
Victoria Lease5cd731a2012-12-19 15:04:21 -0800238 // prepare providers
239 loadProvidersLocked();
240 updateProvidersLocked();
241 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700242
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700243 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700244 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700245 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700246 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800247 @Override
248 public void onChange(boolean selfChange) {
249 synchronized (mLock) {
250 updateProvidersLocked();
251 }
252 }
253 }, UserHandle.USER_ALL);
254 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700255
Victoria Lease38389b62012-09-30 11:44:22 -0700256 // listen for user change
257 IntentFilter intentFilter = new IntentFilter();
258 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
259
260 mContext.registerReceiverAsUser(new BroadcastReceiver() {
261 @Override
262 public void onReceive(Context context, Intent intent) {
263 String action = intent.getAction();
264 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
265 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
266 }
267 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800268 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700269 }
270
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500271 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
272 PackageManager pm = mContext.getPackageManager();
273 String systemPackageName = mContext.getPackageName();
274 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
275
276 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
277 new Intent(FUSED_LOCATION_SERVICE_ACTION),
278 PackageManager.GET_META_DATA, mCurrentUserId);
279 for (ResolveInfo rInfo : rInfos) {
280 String packageName = rInfo.serviceInfo.packageName;
281
282 // Check that the signature is in the list of supported sigs. If it's not in
283 // this list the standard provider binding logic won't bind to it.
284 try {
285 PackageInfo pInfo;
286 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
287 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
288 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
289 ", but has wrong signature, ignoring");
290 continue;
291 }
292 } catch (NameNotFoundException e) {
293 Log.e(TAG, "missing package: " + packageName);
294 continue;
295 }
296
297 // Get the version info
298 if (rInfo.serviceInfo.metaData == null) {
299 Log.w(TAG, "Found fused provider without metadata: " + packageName);
300 continue;
301 }
302
303 int version = rInfo.serviceInfo.metaData.getInt(
304 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
305 if (version == 0) {
306 // This should be the fallback fused location provider.
307
308 // Make sure it's in the system partition.
309 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
310 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
311 continue;
312 }
313
314 // Check that the fallback is signed the same as the OS
315 // as a proxy for coreApp="true"
316 if (pm.checkSignatures(systemPackageName, packageName)
317 != PackageManager.SIGNATURE_MATCH) {
318 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
319 + packageName);
320 continue;
321 }
322
323 // Found a valid fallback.
324 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
325 return;
326 } else {
327 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
328 }
329 }
330
331 throw new IllegalStateException("Unable to find a fused location provider that is in the "
332 + "system partition with version 0 and signed with the platform certificate. "
333 + "Such a package is needed to provide a default fused location provider in the "
334 + "event that no other fused location provider has been installed or is currently "
335 + "available. For example, coreOnly boot mode when decrypting the data "
336 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
337 }
338
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700339 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700340 // create a passive location provider, which is always enabled
341 PassiveProvider passiveProvider = new PassiveProvider(this);
342 addProviderLocked(passiveProvider);
343 mEnabledProviders.add(passiveProvider.getName());
344 mPassiveProvider = passiveProvider;
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700345 // Create a gps location provider
346 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
347 mLocationHandler.getLooper());
Victoria Lease5c24fd02012-10-01 11:00:50 -0700348
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700349 if (GpsLocationProvider.isSupported()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700350 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
351 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
352 addProviderLocked(gpsProvider);
353 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
354 }
355
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700356 /*
357 Load package name(s) containing location provider support.
358 These packages can contain services implementing location providers:
359 Geocoder Provider, Network Location Provider, and
360 Fused Location Provider. They will each be searched for
361 service components implementing these providers.
362 The location framework also has support for installation
363 of new location providers at run-time. The new package does not
364 have to be explicitly listed here, however it must have a signature
365 that matches the signature of at least one package on this list.
366 */
367 Resources resources = mContext.getResources();
368 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500369 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700370 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500371 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
372 Arrays.toString(pkgs));
373 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
374
375 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700376
377 // bind to network provider
378 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
379 mContext,
380 LocationManager.NETWORK_PROVIDER,
381 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700382 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
383 com.android.internal.R.string.config_networkLocationProviderPackageName,
384 com.android.internal.R.array.config_locationProviderPackageNames,
385 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700386 if (networkProvider != null) {
387 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
388 mProxyProviders.add(networkProvider);
389 addProviderLocked(networkProvider);
390 } else {
391 Slog.w(TAG, "no network location provider found");
392 }
393
394 // bind to fused provider
395 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
396 mContext,
397 LocationManager.FUSED_PROVIDER,
398 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700399 com.android.internal.R.bool.config_enableFusedLocationOverlay,
400 com.android.internal.R.string.config_fusedLocationProviderPackageName,
401 com.android.internal.R.array.config_locationProviderPackageNames,
402 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700403 if (fusedLocationProvider != null) {
404 addProviderLocked(fusedLocationProvider);
405 mProxyProviders.add(fusedLocationProvider);
406 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700407 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700408 } else {
409 Slog.e(TAG, "no fused location provider found",
410 new IllegalStateException("Location service needs a fused location provider"));
411 }
412
413 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700414 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
415 com.android.internal.R.bool.config_enableGeocoderOverlay,
416 com.android.internal.R.string.config_geocoderProviderPackageName,
417 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800418 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700419 if (mGeocodeProvider == null) {
420 Slog.e(TAG, "no geocoder provider found");
421 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700422
423 // bind to geofence provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700424 GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
425 com.android.internal.R.bool.config_enableGeofenceOverlay,
426 com.android.internal.R.string.config_geofenceProviderPackageName,
427 com.android.internal.R.array.config_locationProviderPackageNames,
428 mLocationHandler,
429 gpsProvider.getGpsGeofenceProxy());
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700430 if (provider == null) {
431 Slog.e(TAG, "no geofence provider found");
432 }
433
destradaa1af4b022013-07-12 15:43:36 -0700434 // bind to fused provider
435 // TODO: [GeofenceIntegration] bind #getGeofenceHardware() with the GeofenceProxy
436 FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
437 FusedProxy fusedProxy = FusedProxy.createAndBind(
438 mContext,
439 mLocationHandler,
440 flpHardwareProvider.getLocationHardware());
441
442 if(fusedProxy == null) {
443 Slog.e(TAG, "No FusedProvider found.");
444 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700445 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700446
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700448 * Called when the device's active user changes.
449 * @param userId the new active user's UserId
450 */
451 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700452 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800453 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700454 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700455 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700456 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700457 for (LocationProviderInterface p : mProviders) {
458 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700459 }
Victoria Lease38389b62012-09-30 11:44:22 -0700460 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700461 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700462 }
463 }
464
465 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
467 * location updates.
468 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700469 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700470 final int mUid; // uid of receiver
471 final int mPid; // pid of receiver
472 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700473 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 final ILocationListener mListener;
476 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700477 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700478 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700480
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400481 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700482
David Christie0b837452013-07-29 16:02:13 -0700483 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700484 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700485 // True if app ops has started monitoring this receiver for high power (gps) locations.
486 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700487 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700488 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700490 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700491 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700494 if (listener != null) {
495 mKey = listener.asBinder();
496 } else {
497 mKey = intent;
498 }
Victoria Lease37425c32012-10-16 16:08:48 -0700499 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700500 mUid = uid;
501 mPid = pid;
502 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700503 if (workSource != null && workSource.size() <= 0) {
504 workSource = null;
505 }
506 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700507 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700508
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700509 updateMonitoring(true);
510
Victoria Lease0aa28602013-05-29 15:28:26 -0700511 // construct/configure wakelock
512 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700513 if (workSource == null) {
514 workSource = new WorkSource(mUid, mPackageName);
515 }
516 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 }
518
519 @Override
520 public boolean equals(Object otherObj) {
521 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700522 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 }
524 return false;
525 }
526
527 @Override
528 public int hashCode() {
529 return mKey.hashCode();
530 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 @Override
533 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700534 StringBuilder s = new StringBuilder();
535 s.append("Reciever[");
536 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700538 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700540 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700542 for (String p : mUpdateRecords.keySet()) {
543 s.append(" ").append(mUpdateRecords.get(p).toString());
544 }
545 s.append("]");
546 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 }
548
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700549 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700550 if (mHideFromAppOps) {
551 return;
552 }
553
David Christie0b837452013-07-29 16:02:13 -0700554 // First update monitoring of any location request (including high power).
555 mOpMonitoring = updateMonitoring(allow, mOpMonitoring,
556 AppOpsManager.OP_MONITOR_LOCATION);
557
558 // Now update monitoring of high power requests only.
559 // A high power request is any gps request with interval under a threshold.
560 boolean allowHighPower = allow;
561 if (allowHighPower) {
562 UpdateRecord gpsRecord = mUpdateRecords.get(LocationManager.GPS_PROVIDER);
563 if (gpsRecord == null
564 || gpsRecord.mRequest.getInterval() > HIGH_POWER_INTERVAL_MS) {
565 allowHighPower = false;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700566 }
567 }
David Christiec750c1f2013-08-08 12:56:57 -0700568 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700569 mOpHighPowerMonitoring = updateMonitoring(allowHighPower, mOpHighPowerMonitoring,
570 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700571 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
572 // send an intent to notify that a high power request has been added/removed.
573 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
574 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
575 }
David Christie0b837452013-07-29 16:02:13 -0700576 }
577
578 /**
579 * Update AppOps monitoring for a single location request and op type.
580 *
581 * @param allowMonitoring True if monitoring is allowed for this request/op.
582 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
583 * @param op AppOps code for the op to update.
584 * @return True if monitoring is on for this request/op after updating.
585 */
586 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
587 int op) {
588 if (!currentlyMonitoring) {
589 if (allowMonitoring) {
590 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
591 == AppOpsManager.MODE_ALLOWED;
592 }
593 } else {
594 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
595 != AppOpsManager.MODE_ALLOWED) {
596 mAppOps.finishOp(op, mUid, mPackageName);
597 return false;
598 }
599 }
600
601 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700602 }
603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 public boolean isListener() {
605 return mListener != null;
606 }
607
608 public boolean isPendingIntent() {
609 return mPendingIntent != null;
610 }
611
612 public ILocationListener getListener() {
613 if (mListener != null) {
614 return mListener;
615 }
616 throw new IllegalStateException("Request for non-existent listener");
617 }
618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
620 if (mListener != null) {
621 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700622 synchronized (this) {
623 // synchronize to ensure incrementPendingBroadcastsLocked()
624 // is called before decrementPendingBroadcasts()
625 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700626 // call this after broadcasting so we do not increment
627 // if we throw an exeption.
628 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700629 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 } catch (RemoteException e) {
631 return false;
632 }
633 } else {
634 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800635 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
637 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700638 synchronized (this) {
639 // synchronize to ensure incrementPendingBroadcastsLocked()
640 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700641 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700642 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700643 // call this after broadcasting so we do not increment
644 // if we throw an exeption.
645 incrementPendingBroadcastsLocked();
646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 } catch (PendingIntent.CanceledException e) {
648 return false;
649 }
650 }
651 return true;
652 }
653
654 public boolean callLocationChangedLocked(Location location) {
655 if (mListener != null) {
656 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700657 synchronized (this) {
658 // synchronize to ensure incrementPendingBroadcastsLocked()
659 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800660 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700661 // call this after broadcasting so we do not increment
662 // if we throw an exeption.
663 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 } catch (RemoteException e) {
666 return false;
667 }
668 } else {
669 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800670 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700672 synchronized (this) {
673 // synchronize to ensure incrementPendingBroadcastsLocked()
674 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700675 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700676 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700677 // call this after broadcasting so we do not increment
678 // if we throw an exeption.
679 incrementPendingBroadcastsLocked();
680 }
681 } catch (PendingIntent.CanceledException e) {
682 return false;
683 }
684 }
685 return true;
686 }
687
688 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
689 if (mListener != null) {
690 try {
691 synchronized (this) {
692 // synchronize to ensure incrementPendingBroadcastsLocked()
693 // is called before decrementPendingBroadcasts()
694 if (enabled) {
695 mListener.onProviderEnabled(provider);
696 } else {
697 mListener.onProviderDisabled(provider);
698 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700699 // call this after broadcasting so we do not increment
700 // if we throw an exeption.
701 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700702 }
703 } catch (RemoteException e) {
704 return false;
705 }
706 } else {
707 Intent providerIntent = new Intent();
708 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
709 try {
710 synchronized (this) {
711 // synchronize to ensure incrementPendingBroadcastsLocked()
712 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700713 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700714 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700715 // call this after broadcasting so we do not increment
716 // if we throw an exeption.
717 incrementPendingBroadcastsLocked();
718 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 } catch (PendingIntent.CanceledException e) {
720 return false;
721 }
722 }
723 return true;
724 }
725
Nick Pellyf1be6862012-05-15 10:53:42 -0700726 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700728 if (D) Log.d(TAG, "Location listener died");
729
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400730 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 removeUpdatesLocked(this);
732 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700733 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700734 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700735 }
736 }
737
Nick Pellye0fd6932012-07-11 10:26:13 -0700738 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700739 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
740 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400741 synchronized (this) {
742 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700743 }
744 }
745
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400746 // this must be called while synchronized by caller in a synchronized block
747 // containing the sending of the broadcaset
748 private void incrementPendingBroadcastsLocked() {
749 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700750 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400751 }
752 }
753
754 private void decrementPendingBroadcastsLocked() {
755 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700756 if (mWakeLock.isHeld()) {
757 mWakeLock.release();
758 }
759 }
760 }
761
762 public void clearPendingBroadcastsLocked() {
763 if (mPendingBroadcasts > 0) {
764 mPendingBroadcasts = 0;
765 if (mWakeLock.isHeld()) {
766 mWakeLock.release();
767 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700768 }
769 }
770 }
771
Nick Pellye0fd6932012-07-11 10:26:13 -0700772 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700773 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700774 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400775 //the receiver list if it is not found. If it is not found then the
776 //LocationListener was removed when it had a pending broadcast and should
777 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700778 synchronized (mLock) {
779 IBinder binder = listener.asBinder();
780 Receiver receiver = mReceivers.get(binder);
781 if (receiver != null) {
782 synchronized (receiver) {
783 // so wakelock calls will succeed
784 long identity = Binder.clearCallingIdentity();
785 receiver.decrementPendingBroadcastsLocked();
786 Binder.restoreCallingIdentity(identity);
787 }
788 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 }
790 }
791
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700792 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400793 mProviders.add(provider);
794 mProvidersByName.put(provider.getName(), provider);
795 }
796
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700797 private void removeProviderLocked(LocationProviderInterface provider) {
798 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400799 mProviders.remove(provider);
800 mProvidersByName.remove(provider.getName());
801 }
802
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800803 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800804 * Returns "true" if access to the specified location provider is allowed by the current
805 * user's settings. Access to all location providers is forbidden to non-location-provider
806 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800807 *
808 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800809 * @return
810 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800811 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 if (mEnabledProviders.contains(provider)) {
813 return true;
814 }
815 if (mDisabledProviders.contains(provider)) {
816 return false;
817 }
818 // Use system settings
819 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820
Victoria Leaseb711d572012-10-02 13:14:11 -0700821 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 }
823
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700824 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800825 * Returns "true" if access to the specified location provider is allowed by the specified
826 * user's settings. Access to all location providers is forbidden to non-location-provider
827 * processes belonging to background users.
828 *
829 * @param provider the name of the location provider
830 * @param uid the requestor's UID
831 * @return
832 */
833 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
834 if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) {
835 return false;
836 }
837 return isAllowedByCurrentUserSettingsLocked(provider);
838 }
839
840 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700841 * Returns the permission string associated with the specified resolution level.
842 *
843 * @param resolutionLevel the resolution level
844 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700845 */
Victoria Lease37425c32012-10-16 16:08:48 -0700846 private String getResolutionPermission(int resolutionLevel) {
847 switch (resolutionLevel) {
848 case RESOLUTION_LEVEL_FINE:
849 return android.Manifest.permission.ACCESS_FINE_LOCATION;
850 case RESOLUTION_LEVEL_COARSE:
851 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
852 default:
853 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700855 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700856
Victoria Leaseda479c52012-10-15 15:24:16 -0700857 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700858 * Returns the resolution level allowed to the given PID/UID pair.
859 *
860 * @param pid the PID
861 * @param uid the UID
862 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700863 */
Victoria Lease37425c32012-10-16 16:08:48 -0700864 private int getAllowedResolutionLevel(int pid, int uid) {
865 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
866 pid, uid) == PackageManager.PERMISSION_GRANTED) {
867 return RESOLUTION_LEVEL_FINE;
868 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
869 pid, uid) == PackageManager.PERMISSION_GRANTED) {
870 return RESOLUTION_LEVEL_COARSE;
871 } else {
872 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700873 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700874 }
875
876 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700877 * Returns the resolution level allowed to the caller
878 *
879 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700880 */
Victoria Lease37425c32012-10-16 16:08:48 -0700881 private int getCallerAllowedResolutionLevel() {
882 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
883 }
884
885 /**
886 * Throw SecurityException if specified resolution level is insufficient to use geofences.
887 *
888 * @param allowedResolutionLevel resolution level allowed to caller
889 */
890 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
891 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700892 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 }
895
Victoria Lease37425c32012-10-16 16:08:48 -0700896 /**
897 * Return the minimum resolution level required to use the specified location provider.
898 *
899 * @param provider the name of the location provider
900 * @return minimum resolution level required for provider
901 */
902 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700903 if (LocationManager.GPS_PROVIDER.equals(provider) ||
904 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
905 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700906 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700907 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
908 LocationManager.FUSED_PROVIDER.equals(provider)) {
909 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700910 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700911 } else {
912 // mock providers
913 LocationProviderInterface lp = mMockProviders.get(provider);
914 if (lp != null) {
915 ProviderProperties properties = lp.getProperties();
916 if (properties != null) {
917 if (properties.mRequiresSatellite) {
918 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700919 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700920 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
921 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700922 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700923 }
924 }
925 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700926 }
Victoria Lease37425c32012-10-16 16:08:48 -0700927 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700928 }
929
Victoria Lease37425c32012-10-16 16:08:48 -0700930 /**
931 * Throw SecurityException if specified resolution level is insufficient to use the named
932 * location provider.
933 *
934 * @param allowedResolutionLevel resolution level allowed to caller
935 * @param providerName the name of the location provider
936 */
937 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
938 String providerName) {
939 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
940 if (allowedResolutionLevel < requiredResolutionLevel) {
941 switch (requiredResolutionLevel) {
942 case RESOLUTION_LEVEL_FINE:
943 throw new SecurityException("\"" + providerName + "\" location provider " +
944 "requires ACCESS_FINE_LOCATION permission.");
945 case RESOLUTION_LEVEL_COARSE:
946 throw new SecurityException("\"" + providerName + "\" location provider " +
947 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
948 default:
949 throw new SecurityException("Insufficient permission for \"" + providerName +
950 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700951 }
952 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700953 }
954
David Christie82edc9b2013-07-19 11:31:42 -0700955 /**
956 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
957 * for battery).
958 */
David Christie40e57822013-07-30 11:36:48 -0700959 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -0700960 mContext.enforceCallingOrSelfPermission(
961 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
962 }
963
David Christie40e57822013-07-30 11:36:48 -0700964 private void checkUpdateAppOpsAllowed() {
965 mContext.enforceCallingOrSelfPermission(
966 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
967 }
968
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800969 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800970 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
971 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800972 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800973 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800974 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800975 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800976 }
977 return -1;
978 }
979
980 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
981 int op = resolutionLevelToOp(allowedResolutionLevel);
982 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800983 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
984 return false;
985 }
986 }
987 return true;
988 }
989
990 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800991 int op = resolutionLevelToOp(allowedResolutionLevel);
992 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800993 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
994 return false;
995 }
996 }
997 return true;
998 }
999
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001000 /**
1001 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -07001002 * fused, also including ones that are not permitted to
1003 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001004 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001005 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001007 ArrayList<String> out;
1008 synchronized (mLock) {
1009 out = new ArrayList<String>(mProviders.size());
1010 for (LocationProviderInterface provider : mProviders) {
1011 String name = provider.getName();
1012 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001013 continue;
1014 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 out.add(name);
1016 }
1017 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001018
1019 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 return out;
1021 }
1022
Mike Lockwood03ca2162010-04-01 08:10:09 -07001023 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001024 * Return all providers by name, that match criteria and are optionally
1025 * enabled.
1026 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001027 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001028 @Override
1029 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001030 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001031 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001032 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -07001033 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001034 try {
1035 synchronized (mLock) {
1036 out = new ArrayList<String>(mProviders.size());
1037 for (LocationProviderInterface provider : mProviders) {
1038 String name = provider.getName();
1039 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001040 continue;
1041 }
Victoria Lease37425c32012-10-16 16:08:48 -07001042 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001043 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001044 continue;
1045 }
1046 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1047 name, provider.getProperties(), criteria)) {
1048 continue;
1049 }
1050 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001051 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001052 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001053 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001054 } finally {
1055 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001056 }
1057
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001058 if (D) Log.d(TAG, "getProviders()=" + out);
1059 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001060 }
1061
1062 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001063 * Return the name of the best provider given a Criteria object.
1064 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001065 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001066 * has been deprecated as well. So this method now uses
1067 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001068 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001069 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001070 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001071 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001072
1073 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001074 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001075 result = pickBest(providers);
1076 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1077 return result;
1078 }
1079 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001080 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001081 result = pickBest(providers);
1082 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1083 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001084 }
1085
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001086 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001087 return null;
1088 }
1089
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001090 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001091 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001092 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001093 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1094 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001095 } else {
1096 return providers.get(0);
1097 }
1098 }
1099
Nick Pellye0fd6932012-07-11 10:26:13 -07001100 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001101 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1102 LocationProviderInterface p = mProvidersByName.get(provider);
1103 if (p == null) {
1104 throw new IllegalArgumentException("provider=" + provider);
1105 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001106
1107 boolean result = LocationProvider.propertiesMeetCriteria(
1108 p.getName(), p.getProperties(), criteria);
1109 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1110 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001111 }
1112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001114 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001115 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001116 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 boolean isEnabled = p.isEnabled();
1118 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001119 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001121 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001122 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001124 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001125 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001127 }
1128 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001129 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1130 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 }
1132 }
1133
Victoria Leaseb711d572012-10-02 13:14:11 -07001134 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 int listeners = 0;
1136
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001137 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001138 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139
1140 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1143 if (records != null) {
1144 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001145 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -07001147 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001148 // Sends a notification message to the receiver
1149 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1150 if (deadReceivers == null) {
1151 deadReceivers = new ArrayList<Receiver>();
1152 }
1153 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001155 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 }
1158 }
1159
1160 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001161 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 removeUpdatesLocked(deadReceivers.get(i));
1163 }
1164 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 if (enabled) {
1167 p.enable();
1168 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001169 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001170 }
1171 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 }
1175
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001176 private void applyRequirementsLocked(String provider) {
1177 LocationProviderInterface p = mProvidersByName.get(provider);
1178 if (p == null) return;
1179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001181 WorkSource worksource = new WorkSource();
1182 ProviderRequest providerRequest = new ProviderRequest();
1183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001185 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001186 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001187 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1188 record.mReceiver.mAllowedResolutionLevel)) {
1189 LocationRequest locationRequest = record.mRequest;
1190 providerRequest.locationRequests.add(locationRequest);
1191 if (locationRequest.getInterval() < providerRequest.interval) {
1192 providerRequest.reportLocation = true;
1193 providerRequest.interval = locationRequest.getInterval();
1194 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001195 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001196 }
1197 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001198
1199 if (providerRequest.reportLocation) {
1200 // calculate who to blame for power
1201 // This is somewhat arbitrary. We pick a threshold interval
1202 // that is slightly higher that the minimum interval, and
1203 // spread the blame across all applications with a request
1204 // under that threshold.
1205 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1206 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001207 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001208 LocationRequest locationRequest = record.mRequest;
1209 if (locationRequest.getInterval() <= thresholdInterval) {
David Christie82edc9b2013-07-19 11:31:42 -07001210 if (record.mReceiver.mWorkSource != null) {
1211 // Assign blame to another work source.
1212 worksource.add(record.mReceiver.mWorkSource);
1213 } else {
1214 // Assign blame to caller.
1215 worksource.add(
1216 record.mReceiver.mUid,
1217 record.mReceiver.mPackageName);
1218 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001219 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001220 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 }
1223 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001224
1225 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1226 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 }
1228
1229 private class UpdateRecord {
1230 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001231 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001233 Location mLastFixBroadcast;
1234 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235
1236 /**
1237 * Note: must be constructed with lock held.
1238 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001239 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001241 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243
1244 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1245 if (records == null) {
1246 records = new ArrayList<UpdateRecord>();
1247 mRecordsByProvider.put(provider, records);
1248 }
1249 if (!records.contains(this)) {
1250 records.add(this);
1251 }
1252 }
1253
1254 /**
1255 * Method to be called when a record will no longer be used. Calling this multiple times
1256 * must have the same effect as calling it once.
1257 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001258 void disposeLocked(boolean removeReceiver) {
1259 // remove from mRecordsByProvider
1260 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1261 if (globalRecords != null) {
1262 globalRecords.remove(this);
1263 }
1264
1265 if (!removeReceiver) return; // the caller will handle the rest
1266
1267 // remove from Receiver#mUpdateRecords
1268 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1269 if (receiverRecords != null) {
1270 receiverRecords.remove(this.mProvider);
1271
1272 // and also remove the Receiver if it has no more update records
1273 if (removeReceiver && receiverRecords.size() == 0) {
1274 removeUpdatesLocked(mReceiver);
1275 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 }
1278
1279 @Override
1280 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001281 StringBuilder s = new StringBuilder();
1282 s.append("UpdateRecord[");
1283 s.append(mProvider);
1284 s.append(' ').append(mReceiver.mPackageName).append('(');
1285 s.append(mReceiver.mUid).append(')');
1286 s.append(' ').append(mRequest);
1287 s.append(']');
1288 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 }
1291
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001292 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001293 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001294 IBinder binder = listener.asBinder();
1295 Receiver receiver = mReceivers.get(binder);
1296 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001297 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1298 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001299 mReceivers.put(binder, receiver);
1300
1301 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001302 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001303 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001304 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001305 return null;
1306 }
1307 }
1308 return receiver;
1309 }
1310
David Christie82edc9b2013-07-19 11:31:42 -07001311 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001312 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001313 Receiver receiver = mReceivers.get(intent);
1314 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001315 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1316 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001317 mReceivers.put(intent, receiver);
1318 }
1319 return receiver;
1320 }
1321
Victoria Lease37425c32012-10-16 16:08:48 -07001322 /**
1323 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1324 * and consistency requirements.
1325 *
1326 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001327 * @return a version of request that meets the given resolution and consistency requirements
1328 * @hide
1329 */
1330 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1331 LocationRequest sanitizedRequest = new LocationRequest(request);
1332 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1333 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001334 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001335 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001336 break;
1337 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001338 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001339 break;
1340 }
1341 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001342 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1343 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001344 }
Victoria Lease37425c32012-10-16 16:08:48 -07001345 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1346 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001347 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001348 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001349 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001350 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001351 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001352 }
Victoria Lease37425c32012-10-16 16:08:48 -07001353 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001354 }
1355
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001356 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001357 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001358 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001359 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001360 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001361 String[] packages = mPackageManager.getPackagesForUid(uid);
1362 if (packages == null) {
1363 throw new SecurityException("invalid UID " + uid);
1364 }
1365 for (String pkg : packages) {
1366 if (packageName.equals(pkg)) return;
1367 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001368 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001369 }
1370
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001371 private void checkPendingIntent(PendingIntent intent) {
1372 if (intent == null) {
1373 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001374 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001375 }
1376
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001377 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07001378 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001379 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001380 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001381 } else if (intent != null && listener != null) {
1382 throw new IllegalArgumentException("cannot register both listener and intent");
1383 } else if (intent != null) {
1384 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07001385 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001386 } else {
David Christie40e57822013-07-30 11:36:48 -07001387 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001388 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001389 }
1390
Nick Pellye0fd6932012-07-11 10:26:13 -07001391 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001392 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1393 PendingIntent intent, String packageName) {
1394 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1395 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001396 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1397 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1398 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001399 WorkSource workSource = request.getWorkSource();
1400 if (workSource != null && workSource.size() > 0) {
David Christie40e57822013-07-30 11:36:48 -07001401 checkDeviceStatsAllowed();
1402 }
1403 boolean hideFromAppOps = request.getHideFromAppOps();
1404 if (hideFromAppOps) {
1405 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07001406 }
Victoria Lease37425c32012-10-16 16:08:48 -07001407 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001409 final int pid = Binder.getCallingPid();
1410 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001411 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 long identity = Binder.clearCallingIdentity();
1413 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001414 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1415 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001416 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001417
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001418 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001419 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07001420 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07001421 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001422 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 } finally {
1424 Binder.restoreCallingIdentity(identity);
1425 }
1426 }
1427
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001428 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1429 int pid, int uid, String packageName) {
1430 // Figure out the provider. Either its explicitly request (legacy use cases), or
1431 // use the fused provider
1432 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1433 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001434 if (name == null) {
1435 throw new IllegalArgumentException("provider name must not be null");
1436 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001437
1438 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1439 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001440 LocationProviderInterface provider = mProvidersByName.get(name);
1441 if (provider == null) {
1442 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1443 }
1444
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001445 UpdateRecord record = new UpdateRecord(name, request, receiver);
1446 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1447 if (oldRecord != null) {
1448 oldRecord.disposeLocked(false);
1449 }
1450
Victoria Lease09eeaec2013-02-05 11:34:13 -08001451 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001452 if (isProviderEnabled) {
1453 applyRequirementsLocked(name);
1454 } else {
1455 // Notify the listener that updates are currently disabled
1456 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 }
David Christie0b837452013-07-29 16:02:13 -07001458 // Update the monitoring here just in case multiple location requests were added to the
1459 // same receiver (this request may be high power and the initial might not have been).
1460 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 }
1462
Nick Pellye0fd6932012-07-11 10:26:13 -07001463 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001464 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1465 String packageName) {
1466 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001467
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001468 final int pid = Binder.getCallingPid();
1469 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001470
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001471 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07001472 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07001473 boolean hideFromAppOps = false;
1474 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1475 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001476
1477 // providers may use public location API's, need to clear identity
1478 long identity = Binder.clearCallingIdentity();
1479 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001480 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001481 } finally {
1482 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001484 }
1485 }
1486
1487 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001488 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001489
1490 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1491 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1492 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001493 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001494 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 }
1496
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001497 receiver.updateMonitoring(false);
1498
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001499 // Record which providers were associated with this listener
1500 HashSet<String> providers = new HashSet<String>();
1501 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1502 if (oldRecords != null) {
1503 // Call dispose() on the obsolete update records.
1504 for (UpdateRecord record : oldRecords.values()) {
1505 record.disposeLocked(false);
1506 }
1507 // Accumulate providers
1508 providers.addAll(oldRecords.keySet());
1509 }
1510
1511 // update provider
1512 for (String provider : providers) {
1513 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001514 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001515 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 }
1517
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001518 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 }
1520 }
1521
Dianne Hackbornc2293022013-02-06 23:14:49 -08001522 private void applyAllProviderRequirementsLocked() {
1523 for (LocationProviderInterface p : mProviders) {
1524 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001525 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001526 continue;
1527 }
1528
1529 applyRequirementsLocked(p.getName());
1530 }
1531 }
1532
Nick Pellye0fd6932012-07-11 10:26:13 -07001533 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001534 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001535 if (D) Log.d(TAG, "getLastLocation: " + request);
1536 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001537 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001538 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001539 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1540 request.getProvider());
1541 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001542
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001543 final int uid = Binder.getCallingUid();
1544 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001545 try {
1546 if (mBlacklist.isBlacklisted(packageName)) {
1547 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1548 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001549 return null;
1550 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001551
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001552 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1553 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1554 packageName);
1555 return null;
1556 }
1557
Victoria Leaseb711d572012-10-02 13:14:11 -07001558 synchronized (mLock) {
1559 // Figure out the provider. Either its explicitly request (deprecated API's),
1560 // or use the fused provider
1561 String name = request.getProvider();
1562 if (name == null) name = LocationManager.FUSED_PROVIDER;
1563 LocationProviderInterface provider = mProvidersByName.get(name);
1564 if (provider == null) return null;
1565
Victoria Lease09eeaec2013-02-05 11:34:13 -08001566 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001567
David Christie1b9b7b12013-04-15 15:31:11 -07001568 Location location;
1569 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1570 // Make sure that an app with coarse permissions can't get frequent location
1571 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1572 location = mLastLocationCoarseInterval.get(name);
1573 } else {
1574 location = mLastLocation.get(name);
1575 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001576 if (location == null) {
1577 return null;
1578 }
Victoria Lease37425c32012-10-16 16:08:48 -07001579 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001580 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1581 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001582 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001583 }
Victoria Lease37425c32012-10-16 16:08:48 -07001584 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001585 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001586 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001587 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001588 return null;
1589 } finally {
1590 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001591 }
1592 }
1593
1594 @Override
1595 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1596 String packageName) {
1597 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001598 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1599 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001600 checkPendingIntent(intent);
1601 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001602 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1603 request.getProvider());
1604 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001605
Victoria Lease37425c32012-10-16 16:08:48 -07001606 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001607
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001608 // geo-fence manager uses the public location API, need to clear identity
1609 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001610 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1611 // temporary measure until geofences work for secondary users
1612 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1613 return;
1614 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001615 long identity = Binder.clearCallingIdentity();
1616 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001617 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1618 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001619 } finally {
1620 Binder.restoreCallingIdentity(identity);
1621 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001622 }
1623
1624 @Override
1625 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001626 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001627 checkPendingIntent(intent);
1628 checkPackageName(packageName);
1629
1630 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1631
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001632 // geo-fence manager uses the public location API, need to clear identity
1633 long identity = Binder.clearCallingIdentity();
1634 try {
1635 mGeofenceManager.removeFence(geofence, intent);
1636 } finally {
1637 Binder.restoreCallingIdentity(identity);
1638 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001639 }
1640
1641
1642 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001643 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001644 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 return false;
1646 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001647 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1648 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001649 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001651 final int uid = Binder.getCallingUid();
1652 final long ident = Binder.clearCallingIdentity();
1653 try {
Victoria Lease3d5173d2013-02-05 16:07:32 -08001654 if (!checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001655 return false;
1656 }
1657 } finally {
1658 Binder.restoreCallingIdentity(ident);
1659 }
1660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001662 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001664 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 return false;
1666 }
1667 return true;
1668 }
1669
Nick Pellye0fd6932012-07-11 10:26:13 -07001670 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001672 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001673 try {
1674 mGpsStatusProvider.removeGpsStatusListener(listener);
1675 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001676 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001677 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 }
1679 }
1680
Nick Pellye0fd6932012-07-11 10:26:13 -07001681 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001683 if (provider == null) {
1684 // throw NullPointerException to remain compatible with previous implementation
1685 throw new NullPointerException();
1686 }
Victoria Lease37425c32012-10-16 16:08:48 -07001687 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1688 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001691 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 != PackageManager.PERMISSION_GRANTED)) {
1693 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1694 }
1695
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001696 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001697 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001698 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001699
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001700 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 }
1702 }
1703
Nick Pellye0fd6932012-07-11 10:26:13 -07001704 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001705 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001706 if (Binder.getCallingUid() != Process.myUid()) {
1707 throw new SecurityException(
1708 "calling sendNiResponse from outside of the system is not allowed");
1709 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001710 try {
1711 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001712 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001713 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001714 return false;
1715 }
1716 }
1717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001719 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001720 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 * accessed by the caller
1722 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001723 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001724 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001725 if (mProvidersByName.get(provider) == null) {
1726 return null;
1727 }
1728
Victoria Lease37425c32012-10-16 16:08:48 -07001729 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1730 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001732 LocationProviderInterface p;
1733 synchronized (mLock) {
1734 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 }
1736
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001737 if (p == null) return null;
1738 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 }
1740
Nick Pellye0fd6932012-07-11 10:26:13 -07001741 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001743 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1744 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001745 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1746
Victoria Lease09eeaec2013-02-05 11:34:13 -08001747 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001748 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001749 try {
1750 synchronized (mLock) {
1751 LocationProviderInterface p = mProvidersByName.get(provider);
1752 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001753
Victoria Lease09eeaec2013-02-05 11:34:13 -08001754 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07001755 }
1756 } finally {
1757 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001758 }
1759 }
1760
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001761 /**
1762 * Returns "true" if the UID belongs to a bound location provider.
1763 *
1764 * @param uid the uid
1765 * @return true if uid belongs to a bound location provider
1766 */
1767 private boolean isUidALocationProvider(int uid) {
1768 if (uid == Process.SYSTEM_UID) {
1769 return true;
1770 }
1771 if (mGeocodeProvider != null) {
1772 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true;
1773 }
1774 for (LocationProviderProxy proxy : mProxyProviders) {
1775 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true;
1776 }
1777 return false;
1778 }
1779
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001780 private void checkCallerIsProvider() {
1781 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1782 == PackageManager.PERMISSION_GRANTED) {
1783 return;
1784 }
1785
1786 // Previously we only used the INSTALL_LOCATION_PROVIDER
1787 // check. But that is system or signature
1788 // protection level which is not flexible enough for
1789 // providers installed oustide the system image. So
1790 // also allow providers with a UID matching the
1791 // currently bound package name
1792
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001793 if (isUidALocationProvider(Binder.getCallingUid())) {
1794 return;
1795 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001796
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001797 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1798 "or UID of a currently bound location provider");
1799 }
1800
1801 private boolean doesPackageHaveUid(int uid, String packageName) {
1802 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 return false;
1804 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001805 try {
1806 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1807 if (appInfo.uid != uid) {
1808 return false;
1809 }
1810 } catch (NameNotFoundException e) {
1811 return false;
1812 }
1813 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 }
1815
Nick Pellye0fd6932012-07-11 10:26:13 -07001816 @Override
Mike Lockwooda4903f252010-02-17 06:42:23 -05001817 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001818 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001819
Nick Pelly2eeeec22012-07-18 13:13:37 -07001820 if (!location.isComplete()) {
1821 Log.w(TAG, "Dropping incomplete location: " + location);
1822 return;
1823 }
1824
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001825 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1826 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f252010-02-17 06:42:23 -05001827 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001828 mLocationHandler.sendMessageAtFrontOfQueue(m);
1829 }
1830
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001831
Laurent Tu75defb62012-11-01 16:21:52 -07001832 private static boolean shouldBroadcastSafe(
1833 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 // Always broadcast the first update
1835 if (lastLoc == null) {
1836 return true;
1837 }
1838
Nick Pellyf1be6862012-05-15 10:53:42 -07001839 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001840 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07001841 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
1842 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001843 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001844 return false;
1845 }
1846
1847 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001848 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 if (minDistance > 0.0) {
1850 if (loc.distanceTo(lastLoc) <= minDistance) {
1851 return false;
1852 }
1853 }
1854
Laurent Tu75defb62012-11-01 16:21:52 -07001855 // Check whether sufficient number of udpates is left
1856 if (record.mRequest.getNumUpdates() <= 0) {
1857 return false;
1858 }
1859
1860 // Check whether the expiry date has passed
1861 if (record.mRequest.getExpireAt() < now) {
1862 return false;
1863 }
1864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 return true;
1866 }
1867
Mike Lockwooda4903f252010-02-17 06:42:23 -05001868 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001869 if (D) Log.d(TAG, "incoming location: " + location);
1870
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001871 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f252010-02-17 06:42:23 -05001872 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873
Laurent Tu60ec50a2012-10-04 17:00:10 -07001874 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001875 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001876 if (p == null) return;
1877
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001878 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001879 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1880 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001881 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001882 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001883 lastLocation = new Location(provider);
1884 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001885 } else {
1886 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1887 if (noGPSLocation == null && lastNoGPSLocation != null) {
1888 // New location has no no-GPS location: adopt last no-GPS location. This is set
1889 // directly into location because we do not want to notify COARSE clients.
1890 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1891 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001892 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001893 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894
David Christie1b9b7b12013-04-15 15:31:11 -07001895 // Update last known coarse interval location if enough time has passed.
1896 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
1897 if (lastLocationCoarseInterval == null) {
1898 lastLocationCoarseInterval = new Location(location);
1899 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
1900 }
1901 long timeDiffNanos = location.getElapsedRealtimeNanos()
1902 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
1903 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
1904 lastLocationCoarseInterval.set(location);
1905 }
1906 // Don't ever return a coarse location that is more recent than the allowed update
1907 // interval (i.e. don't allow an app to keep registering and unregistering for
1908 // location updates to overcome the minimum interval).
1909 noGPSLocation =
1910 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1911
Laurent Tu60ec50a2012-10-04 17:00:10 -07001912 // Skip if there are no UpdateRecords for this provider.
1913 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1914 if (records == null || records.size() == 0) return;
1915
Victoria Lease09016ab2012-09-16 12:33:15 -07001916 // Fetch coarse location
1917 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07001918 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001919 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1920 }
1921
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 // Fetch latest status update time
1923 long newStatusUpdateTime = p.getStatusUpdateTime();
1924
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001925 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 Bundle extras = new Bundle();
1927 int status = p.getStatus(extras);
1928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001930 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001932 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001933 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001934 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001935 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001936
Victoria Lease269518e2012-10-29 08:25:39 -07001937 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Victoria Lease2f5b97c2013-05-07 14:22:02 -07001938 if (receiverUserId != mCurrentUserId && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001939 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001940 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001941 " (current user: " + mCurrentUserId + ", app: " +
1942 receiver.mPackageName + ")");
1943 }
1944 continue;
1945 }
1946
Nick Pelly4035f5a2012-08-17 14:43:49 -07001947 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1948 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1949 receiver.mPackageName);
1950 continue;
1951 }
1952
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001953 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
1954 receiver.mAllowedResolutionLevel)) {
1955 if (D) Log.d(TAG, "skipping loc update for no op app: " +
1956 receiver.mPackageName);
1957 continue;
1958 }
1959
Victoria Lease09016ab2012-09-16 12:33:15 -07001960 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001961 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1962 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001963 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001964 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001965 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001966 if (notifyLocation != null) {
1967 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001968 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001969 if (lastLoc == null) {
1970 lastLoc = new Location(notifyLocation);
1971 r.mLastFixBroadcast = lastLoc;
1972 } else {
1973 lastLoc.set(notifyLocation);
1974 }
1975 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1976 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1977 receiverDead = true;
1978 }
Laurent Tu75defb62012-11-01 16:21:52 -07001979 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 }
1981 }
1982
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001983 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001985 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001987 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001989 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001990 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001991 }
1992 }
1993
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001994 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001995 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001996 if (deadUpdateRecords == null) {
1997 deadUpdateRecords = new ArrayList<UpdateRecord>();
1998 }
1999 deadUpdateRecords.add(r);
2000 }
2001 // track dead receivers
2002 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002003 if (deadReceivers == null) {
2004 deadReceivers = new ArrayList<Receiver>();
2005 }
2006 if (!deadReceivers.contains(receiver)) {
2007 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 }
2009 }
2010 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002011
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002012 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002014 for (Receiver receiver : deadReceivers) {
2015 removeUpdatesLocked(receiver);
2016 }
2017 }
2018 if (deadUpdateRecords != null) {
2019 for (UpdateRecord r : deadUpdateRecords) {
2020 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 }
Victoria Lease8b38b292012-12-04 15:04:43 -08002022 applyRequirementsLocked(provider);
2023 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 }
2025
2026 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08002027 public LocationWorkerHandler(Looper looper) {
2028 super(looper, null, true);
2029 }
2030
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 @Override
2032 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002033 switch (msg.what) {
2034 case MSG_LOCATION_CHANGED:
2035 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2036 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 }
2038 }
2039 }
2040
Victoria Lease54ca7aef22013-01-08 09:39:50 -08002041 private boolean isMockProvider(String provider) {
2042 synchronized (mLock) {
2043 return mMockProviders.containsKey(provider);
2044 }
2045 }
2046
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002047 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7aef22013-01-08 09:39:50 -08002048 // create a working copy of the incoming Location so that the service can modify it without
2049 // disturbing the caller's copy
2050 Location myLocation = new Location(location);
2051 String provider = myLocation.getProvider();
2052
2053 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2054 // bit if location did not come from a mock provider because passive/fused providers can
2055 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2056 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2057 myLocation.setIsFromMockProvider(true);
2058 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08002059
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002060 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08002061 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2062 if (!passive) {
2063 // notify passive provider of the new location
2064 mPassiveProvider.updateLocation(myLocation);
2065 }
Victoria Lease54ca7aef22013-01-08 09:39:50 -08002066 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002068 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002070
Mike Lockwoode97ae402010-09-29 15:23:46 -04002071 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2072 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002073 public void onPackageDisappeared(String packageName, int reason) {
2074 // remove all receivers associated with this package name
2075 synchronized (mLock) {
2076 ArrayList<Receiver> deadReceivers = null;
2077
2078 for (Receiver receiver : mReceivers.values()) {
2079 if (receiver.mPackageName.equals(packageName)) {
2080 if (deadReceivers == null) {
2081 deadReceivers = new ArrayList<Receiver>();
2082 }
2083 deadReceivers.add(receiver);
2084 }
2085 }
2086
2087 // perform removal outside of mReceivers loop
2088 if (deadReceivers != null) {
2089 for (Receiver receiver : deadReceivers) {
2090 removeUpdatesLocked(receiver);
2091 }
2092 }
2093 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002094 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002095 };
2096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002097 // Geocoder
2098
Nick Pellye0fd6932012-07-11 10:26:13 -07002099 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002100 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002101 return mGeocodeProvider != null;
2102 }
2103
Nick Pellye0fd6932012-07-11 10:26:13 -07002104 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002105 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002106 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002107 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002108 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2109 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002111 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002112 }
2113
Mike Lockwooda55c3212009-04-15 11:10:11 -04002114
Nick Pellye0fd6932012-07-11 10:26:13 -07002115 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002117 double lowerLeftLatitude, double lowerLeftLongitude,
2118 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002119 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002120
2121 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002122 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2123 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2124 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002125 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002126 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002127 }
2128
2129 // Mock Providers
2130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002131 private void checkMockPermissionsSafe() {
2132 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2133 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2134 if (!allowMocks) {
2135 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2136 }
2137
2138 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2139 PackageManager.PERMISSION_GRANTED) {
2140 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07002141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002142 }
2143
Nick Pellye0fd6932012-07-11 10:26:13 -07002144 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002145 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002146 checkMockPermissionsSafe();
2147
Mike Lockwooda4903f252010-02-17 06:42:23 -05002148 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2149 throw new IllegalArgumentException("Cannot mock the passive location provider");
2150 }
2151
Mike Lockwood86328a92009-10-23 08:38:25 -04002152 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002153 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002154 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002155 // remove the real provider if we are replacing GPS or network provider
2156 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002157 || LocationManager.NETWORK_PROVIDER.equals(name)
2158 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002159 LocationProviderInterface p = mProvidersByName.get(name);
2160 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002161 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002162 }
2163 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002164 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002165 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2166 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002167 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002168 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002169 mLastLocation.put(name, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002170 mLastLocationCoarseInterval.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 updateProvidersLocked();
2172 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002173 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002174 }
2175
Nick Pellye0fd6932012-07-11 10:26:13 -07002176 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002177 public void removeTestProvider(String provider) {
2178 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002179 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09002180 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002181 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002182 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2183 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002184 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002185 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002186
2187 // reinstate real provider if available
2188 LocationProviderInterface realProvider = mRealProviders.get(provider);
2189 if (realProvider != null) {
2190 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002191 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002192 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002193 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002195 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196 }
2197 }
2198
Nick Pellye0fd6932012-07-11 10:26:13 -07002199 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 public void setTestProviderLocation(String provider, Location loc) {
2201 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002202 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002203 MockProvider mockProvider = mMockProviders.get(provider);
2204 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002205 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2206 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002207 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2208 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002209 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002210 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211 }
2212 }
2213
Nick Pellye0fd6932012-07-11 10:26:13 -07002214 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 public void clearTestProviderLocation(String provider) {
2216 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002217 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002218 MockProvider mockProvider = mMockProviders.get(provider);
2219 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002220 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2221 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002222 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002223 }
2224 }
2225
Nick Pellye0fd6932012-07-11 10:26:13 -07002226 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 public void setTestProviderEnabled(String provider, boolean enabled) {
2228 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002229 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002230 MockProvider mockProvider = mMockProviders.get(provider);
2231 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2233 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002234 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002235 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002236 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002237 mEnabledProviders.add(provider);
2238 mDisabledProviders.remove(provider);
2239 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002240 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002241 mEnabledProviders.remove(provider);
2242 mDisabledProviders.add(provider);
2243 }
2244 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002245 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002246 }
2247 }
2248
Nick Pellye0fd6932012-07-11 10:26:13 -07002249 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 public void clearTestProviderEnabled(String provider) {
2251 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002252 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002253 MockProvider mockProvider = mMockProviders.get(provider);
2254 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002255 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2256 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002257 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 mEnabledProviders.remove(provider);
2259 mDisabledProviders.remove(provider);
2260 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002261 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002262 }
2263 }
2264
Nick Pellye0fd6932012-07-11 10:26:13 -07002265 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002266 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2267 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002268 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002269 MockProvider mockProvider = mMockProviders.get(provider);
2270 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002271 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2272 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002273 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002274 }
2275 }
2276
Nick Pellye0fd6932012-07-11 10:26:13 -07002277 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002278 public void clearTestProviderStatus(String provider) {
2279 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002280 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002281 MockProvider mockProvider = mMockProviders.get(provider);
2282 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002283 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2284 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002285 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002286 }
2287 }
2288
2289 private void log(String log) {
2290 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002291 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002292 }
2293 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002294
2295 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002296 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2297 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2298 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002299 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 + Binder.getCallingPid()
2301 + ", uid=" + Binder.getCallingUid());
2302 return;
2303 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002304
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002305 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002306 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002307 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002308 for (Receiver receiver : mReceivers.values()) {
2309 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002311 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002312 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2313 pw.println(" " + entry.getKey() + ":");
2314 for (UpdateRecord record : entry.getValue()) {
2315 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002316 }
2317 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002318 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002319 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2320 String provider = entry.getKey();
2321 Location location = entry.getValue();
2322 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002323 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002324
David Christie1b9b7b12013-04-15 15:31:11 -07002325 pw.println(" Last Known Locations Coarse Intervals:");
2326 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2327 String provider = entry.getKey();
2328 Location location = entry.getValue();
2329 pw.println(" " + provider + ": " + location);
2330 }
2331
Nick Pellye0fd6932012-07-11 10:26:13 -07002332 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002334 if (mEnabledProviders.size() > 0) {
2335 pw.println(" Enabled Providers:");
2336 for (String i : mEnabledProviders) {
2337 pw.println(" " + i);
2338 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002340 }
2341 if (mDisabledProviders.size() > 0) {
2342 pw.println(" Disabled Providers:");
2343 for (String i : mDisabledProviders) {
2344 pw.println(" " + i);
2345 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002346 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002347 pw.append(" ");
2348 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002349 if (mMockProviders.size() > 0) {
2350 pw.println(" Mock Providers:");
2351 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002352 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002353 }
2354 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002355
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002356 pw.append(" fudger: ");
2357 mLocationFudger.dump(fd, pw, args);
2358
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002359 if (args.length > 0 && "short".equals(args[0])) {
2360 return;
2361 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002362 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002363 pw.print(provider.getName() + " Internal State");
2364 if (provider instanceof LocationProviderProxy) {
2365 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2366 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002367 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002368 pw.println(":");
2369 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002371 }
2372 }
2373}