blob: 03b5e12a40296d0974802fbbc70c5acae208aaea [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborna06de0f2012-12-11 16:34:47 -080019import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070021import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070025import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070026import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050027import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070029import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050030import android.content.pm.ResolveInfo;
31import android.content.pm.Signature;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050032import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070033import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070035import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050036import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070037import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040039import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.location.ILocationListener;
41import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040042import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.location.Location;
44import android.location.LocationManager;
45import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070046import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.Binder;
48import android.os.Bundle;
49import android.os.Handler;
Victoria Lease5cd731a2012-12-19 15:04:21 -080050import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070052import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.Message;
54import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070055import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.RemoteException;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080057import android.os.ServiceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070058import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070059import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070060import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080063import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
Dianne Hackborna06de0f2012-12-11 16:34:47 -080065import com.android.internal.app.IAppOpsService;
Mike Lockwoode97ae402010-09-29 15:23:46 -040066import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070067import com.android.internal.location.ProviderProperties;
68import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040069import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070070import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040071import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070072import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070073import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040074import com.android.server.location.LocationProviderInterface;
75import com.android.server.location.LocationProviderProxy;
76import com.android.server.location.MockProvider;
77import com.android.server.location.PassiveProvider;
78
79import java.io.FileDescriptor;
80import java.io.PrintWriter;
81import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070082import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040083import java.util.HashMap;
84import java.util.HashSet;
85import java.util.List;
86import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040087import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
89/**
90 * The service class that manages LocationProviders and issues location
91 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 */
Victoria Lease5cd731a2012-12-19 15:04:21 -080093public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 private static final String TAG = "LocationManagerService";
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;
98 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099
Victoria Lease37425c32012-10-16 16:08:48 -0700100 // Location resolution level: no location data whatsoever
101 private static final int RESOLUTION_LEVEL_NONE = 0;
102 // Location resolution level: coarse location data only
103 private static final int RESOLUTION_LEVEL_COARSE = 1;
104 // Location resolution level: fine location data
105 private static final int RESOLUTION_LEVEL_FINE = 2;
106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700108 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700110 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400111 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700112 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
113
114 private static final String NETWORK_LOCATION_SERVICE_ACTION =
115 "com.android.location.service.v2.NetworkLocationProvider";
116 private static final String FUSED_LOCATION_SERVICE_ACTION =
117 "com.android.location.service.FusedLocationProvider";
118
119 private static final int MSG_LOCATION_CHANGED = 1;
120
Nick Pellyf1be6862012-05-15 10:53:42 -0700121 // Location Providers may sometimes deliver location updates
122 // slightly faster that requested - provide grace period so
123 // we don't unnecessarily filter events that are otherwise on
124 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700125 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700126
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700127 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
128
129 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800130 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700131
132 // used internally for synchronization
133 private final Object mLock = new Object();
134
Victoria Lease5cd731a2012-12-19 15:04:21 -0800135 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700136 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700137 private GeofenceManager mGeofenceManager;
138 private PowerManager.WakeLock mWakeLock;
139 private PackageManager mPackageManager;
140 private GeocoderProxy mGeocodeProvider;
141 private IGpsStatusProvider mGpsStatusProvider;
142 private INetInitiatedListener mNetInitiatedListener;
143 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700144 private PassiveProvider mPassiveProvider; // track passive provider for special cases
145 private LocationBlacklist mBlacklist;
Victoria Lease5cd731a2012-12-19 15:04:21 -0800146 private HandlerThread mHandlerThread;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700147
148 // --- fields below are protected by mWakeLock ---
149 private int mPendingBroadcasts;
150
151 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 // Set of providers that are explicitly enabled
153 private final Set<String> mEnabledProviders = new HashSet<String>();
154
155 // Set of providers that are explicitly disabled
156 private final Set<String> mDisabledProviders = new HashSet<String>();
157
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700158 // Mock (test) providers
159 private final HashMap<String, MockProvider> mMockProviders =
160 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400163 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700165 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500166 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // real providers, saved here when mocked out
170 private final HashMap<String, LocationProviderInterface> mRealProviders =
171 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700173 // mapping from provider name to provider
174 private final HashMap<String, LocationProviderInterface> mProvidersByName =
175 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 // mapping from provider name to all its UpdateRecords
178 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
179 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700180
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 // mapping from provider name to last known location
182 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700184 // all providers that operate over proxy, for authorizing incoming location
185 private final ArrayList<LocationProviderProxy> mProxyProviders =
186 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187
Victoria Lease38389b62012-09-30 11:44:22 -0700188 // current active user on the device - other users are denied location data
189 private int mCurrentUserId = UserHandle.USER_OWNER;
190
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700191 public LocationManagerService(Context context) {
192 super();
193 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800194 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800195
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196 if (D) Log.d(TAG, "Constructed");
197
198 // most startup is deferred until systemReady()
199 }
200
201 public void systemReady() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700202 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800203 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700204
Victoria Lease5cd731a2012-12-19 15:04:21 -0800205 // fetch package manager
206 mPackageManager = mContext.getPackageManager();
207
208 // prepare wake lock
209 PowerManager powerManager =
210 (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
211 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
212
213 // prepare worker thread
214 mHandlerThread = new HandlerThread(THREAD_NAME, Process.THREAD_PRIORITY_BACKGROUND);
215 mHandlerThread.start();
216 mLocationHandler = new LocationWorkerHandler(mHandlerThread.getLooper());
217
218 // prepare mLocationHandler's dependents
219 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
220 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
221 mBlacklist.init();
222 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
223
224 // prepare providers
225 loadProvidersLocked();
226 updateProvidersLocked();
227 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700228
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700229 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700230 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700231 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700232 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800233 @Override
234 public void onChange(boolean selfChange) {
235 synchronized (mLock) {
236 updateProvidersLocked();
237 }
238 }
239 }, UserHandle.USER_ALL);
240 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700241
Victoria Lease38389b62012-09-30 11:44:22 -0700242 // listen for user change
243 IntentFilter intentFilter = new IntentFilter();
244 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
245
246 mContext.registerReceiverAsUser(new BroadcastReceiver() {
247 @Override
248 public void onReceive(Context context, Intent intent) {
249 String action = intent.getAction();
250 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
251 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
252 }
253 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800254 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700255 }
256
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500257 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
258 PackageManager pm = mContext.getPackageManager();
259 String systemPackageName = mContext.getPackageName();
260 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
261
262 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
263 new Intent(FUSED_LOCATION_SERVICE_ACTION),
264 PackageManager.GET_META_DATA, mCurrentUserId);
265 for (ResolveInfo rInfo : rInfos) {
266 String packageName = rInfo.serviceInfo.packageName;
267
268 // Check that the signature is in the list of supported sigs. If it's not in
269 // this list the standard provider binding logic won't bind to it.
270 try {
271 PackageInfo pInfo;
272 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
273 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
274 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
275 ", but has wrong signature, ignoring");
276 continue;
277 }
278 } catch (NameNotFoundException e) {
279 Log.e(TAG, "missing package: " + packageName);
280 continue;
281 }
282
283 // Get the version info
284 if (rInfo.serviceInfo.metaData == null) {
285 Log.w(TAG, "Found fused provider without metadata: " + packageName);
286 continue;
287 }
288
289 int version = rInfo.serviceInfo.metaData.getInt(
290 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
291 if (version == 0) {
292 // This should be the fallback fused location provider.
293
294 // Make sure it's in the system partition.
295 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
296 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
297 continue;
298 }
299
300 // Check that the fallback is signed the same as the OS
301 // as a proxy for coreApp="true"
302 if (pm.checkSignatures(systemPackageName, packageName)
303 != PackageManager.SIGNATURE_MATCH) {
304 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
305 + packageName);
306 continue;
307 }
308
309 // Found a valid fallback.
310 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
311 return;
312 } else {
313 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
314 }
315 }
316
317 throw new IllegalStateException("Unable to find a fused location provider that is in the "
318 + "system partition with version 0 and signed with the platform certificate. "
319 + "Such a package is needed to provide a default fused location provider in the "
320 + "event that no other fused location provider has been installed or is currently "
321 + "available. For example, coreOnly boot mode when decrypting the data "
322 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
323 }
324
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700325 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700326 // create a passive location provider, which is always enabled
327 PassiveProvider passiveProvider = new PassiveProvider(this);
328 addProviderLocked(passiveProvider);
329 mEnabledProviders.add(passiveProvider.getName());
330 mPassiveProvider = passiveProvider;
331
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700332 if (GpsLocationProvider.isSupported()) {
333 // Create a gps location provider
Victoria Lease5cd731a2012-12-19 15:04:21 -0800334 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
335 mLocationHandler.getLooper());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700336 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
337 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
338 addProviderLocked(gpsProvider);
339 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
340 }
341
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700342 /*
343 Load package name(s) containing location provider support.
344 These packages can contain services implementing location providers:
345 Geocoder Provider, Network Location Provider, and
346 Fused Location Provider. They will each be searched for
347 service components implementing these providers.
348 The location framework also has support for installation
349 of new location providers at run-time. The new package does not
350 have to be explicitly listed here, however it must have a signature
351 that matches the signature of at least one package on this list.
352 */
353 Resources resources = mContext.getResources();
354 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500355 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700356 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500357 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
358 Arrays.toString(pkgs));
359 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
360
361 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700362
363 // bind to network provider
364 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
365 mContext,
366 LocationManager.NETWORK_PROVIDER,
367 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700368 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700369 if (networkProvider != null) {
370 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
371 mProxyProviders.add(networkProvider);
372 addProviderLocked(networkProvider);
373 } else {
374 Slog.w(TAG, "no network location provider found");
375 }
376
377 // bind to fused provider
378 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
379 mContext,
380 LocationManager.FUSED_PROVIDER,
381 FUSED_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700382 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700383 if (fusedLocationProvider != null) {
384 addProviderLocked(fusedLocationProvider);
385 mProxyProviders.add(fusedLocationProvider);
386 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700387 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700388 } else {
389 Slog.e(TAG, "no fused location provider found",
390 new IllegalStateException("Location service needs a fused location provider"));
391 }
392
393 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700394 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
Victoria Lease5cd731a2012-12-19 15:04:21 -0800395 mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700396 if (mGeocodeProvider == null) {
397 Slog.e(TAG, "no geocoder provider found");
398 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700399 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700402 * Called when the device's active user changes.
403 * @param userId the new active user's UserId
404 */
405 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700406 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700407 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700408 mLastLocation.clear();
409 for (LocationProviderInterface p : mProviders) {
410 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
Victoria Lease269518e2012-10-29 08:25:39 -0700411 p.switchUser(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700412 }
Victoria Lease38389b62012-09-30 11:44:22 -0700413 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700414 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700415 }
416 }
417
418 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
420 * location updates.
421 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700422 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700423 final int mUid; // uid of receiver
424 final int mPid; // pid of receiver
425 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700426 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 final ILocationListener mListener;
429 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700431
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400432 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700433
Mike Lockwood48f17512009-04-23 09:12:08 -0700434 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700436 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
437 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700440 if (listener != null) {
441 mKey = listener.asBinder();
442 } else {
443 mKey = intent;
444 }
Victoria Lease37425c32012-10-16 16:08:48 -0700445 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700446 mUid = uid;
447 mPid = pid;
448 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 }
450
451 @Override
452 public boolean equals(Object otherObj) {
453 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700454 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 }
456 return false;
457 }
458
459 @Override
460 public int hashCode() {
461 return mKey.hashCode();
462 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 @Override
465 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700466 StringBuilder s = new StringBuilder();
467 s.append("Reciever[");
468 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700470 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700472 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700474 for (String p : mUpdateRecords.keySet()) {
475 s.append(" ").append(mUpdateRecords.get(p).toString());
476 }
477 s.append("]");
478 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 }
480
481 public boolean isListener() {
482 return mListener != null;
483 }
484
485 public boolean isPendingIntent() {
486 return mPendingIntent != null;
487 }
488
489 public ILocationListener getListener() {
490 if (mListener != null) {
491 return mListener;
492 }
493 throw new IllegalStateException("Request for non-existent listener");
494 }
495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
497 if (mListener != null) {
498 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700499 synchronized (this) {
500 // synchronize to ensure incrementPendingBroadcastsLocked()
501 // is called before decrementPendingBroadcasts()
502 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700503 // call this after broadcasting so we do not increment
504 // if we throw an exeption.
505 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 } catch (RemoteException e) {
508 return false;
509 }
510 } else {
511 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800512 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
514 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700515 synchronized (this) {
516 // synchronize to ensure incrementPendingBroadcastsLocked()
517 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700518 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700519 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700520 // call this after broadcasting so we do not increment
521 // if we throw an exeption.
522 incrementPendingBroadcastsLocked();
523 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 } catch (PendingIntent.CanceledException e) {
525 return false;
526 }
527 }
528 return true;
529 }
530
531 public boolean callLocationChangedLocked(Location location) {
532 if (mListener != null) {
533 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700534 synchronized (this) {
535 // synchronize to ensure incrementPendingBroadcastsLocked()
536 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800537 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700538 // call this after broadcasting so we do not increment
539 // if we throw an exeption.
540 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 } catch (RemoteException e) {
543 return false;
544 }
545 } else {
546 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800547 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700549 synchronized (this) {
550 // synchronize to ensure incrementPendingBroadcastsLocked()
551 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700552 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700553 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700554 // call this after broadcasting so we do not increment
555 // if we throw an exeption.
556 incrementPendingBroadcastsLocked();
557 }
558 } catch (PendingIntent.CanceledException e) {
559 return false;
560 }
561 }
562 return true;
563 }
564
565 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
566 if (mListener != null) {
567 try {
568 synchronized (this) {
569 // synchronize to ensure incrementPendingBroadcastsLocked()
570 // is called before decrementPendingBroadcasts()
571 if (enabled) {
572 mListener.onProviderEnabled(provider);
573 } else {
574 mListener.onProviderDisabled(provider);
575 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700576 // call this after broadcasting so we do not increment
577 // if we throw an exeption.
578 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700579 }
580 } catch (RemoteException e) {
581 return false;
582 }
583 } else {
584 Intent providerIntent = new Intent();
585 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
586 try {
587 synchronized (this) {
588 // synchronize to ensure incrementPendingBroadcastsLocked()
589 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700590 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700591 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700592 // call this after broadcasting so we do not increment
593 // if we throw an exeption.
594 incrementPendingBroadcastsLocked();
595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 } catch (PendingIntent.CanceledException e) {
597 return false;
598 }
599 }
600 return true;
601 }
602
Nick Pellyf1be6862012-05-15 10:53:42 -0700603 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700605 if (D) Log.d(TAG, "Location listener died");
606
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400607 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 removeUpdatesLocked(this);
609 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700610 synchronized (this) {
611 if (mPendingBroadcasts > 0) {
612 LocationManagerService.this.decrementPendingBroadcasts();
613 mPendingBroadcasts = 0;
614 }
615 }
616 }
617
Nick Pellye0fd6932012-07-11 10:26:13 -0700618 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700619 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
620 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400621 synchronized (this) {
622 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700623 }
624 }
625
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400626 // this must be called while synchronized by caller in a synchronized block
627 // containing the sending of the broadcaset
628 private void incrementPendingBroadcastsLocked() {
629 if (mPendingBroadcasts++ == 0) {
630 LocationManagerService.this.incrementPendingBroadcasts();
631 }
632 }
633
634 private void decrementPendingBroadcastsLocked() {
635 if (--mPendingBroadcasts == 0) {
636 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700637 }
638 }
639 }
640
Nick Pellye0fd6932012-07-11 10:26:13 -0700641 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700642 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400643 //Do not use getReceiver here as that will add the ILocationListener to
644 //the receiver list if it is not found. If it is not found then the
645 //LocationListener was removed when it had a pending broadcast and should
646 //not be added back.
647 IBinder binder = listener.asBinder();
648 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700649 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400650 synchronized (receiver) {
651 // so wakelock calls will succeed
652 long identity = Binder.clearCallingIdentity();
653 receiver.decrementPendingBroadcastsLocked();
654 Binder.restoreCallingIdentity(identity);
655 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 }
657 }
658
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700659 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400660 mProviders.add(provider);
661 mProvidersByName.put(provider.getName(), provider);
662 }
663
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700664 private void removeProviderLocked(LocationProviderInterface provider) {
665 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400666 mProviders.remove(provider);
667 mProvidersByName.remove(provider.getName());
668 }
669
Mike Lockwood3d12b512009-04-21 23:25:35 -0700670
Victoria Lease269518e2012-10-29 08:25:39 -0700671 private boolean isAllowedBySettingsLocked(String provider, int userId) {
672 if (userId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700673 return false;
674 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 if (mEnabledProviders.contains(provider)) {
676 return true;
677 }
678 if (mDisabledProviders.contains(provider)) {
679 return false;
680 }
681 // Use system settings
682 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683
Victoria Leaseb711d572012-10-02 13:14:11 -0700684 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 }
686
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700687 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700688 * Returns the permission string associated with the specified resolution level.
689 *
690 * @param resolutionLevel the resolution level
691 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700692 */
Victoria Lease37425c32012-10-16 16:08:48 -0700693 private String getResolutionPermission(int resolutionLevel) {
694 switch (resolutionLevel) {
695 case RESOLUTION_LEVEL_FINE:
696 return android.Manifest.permission.ACCESS_FINE_LOCATION;
697 case RESOLUTION_LEVEL_COARSE:
698 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
699 default:
700 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700702 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700703
Victoria Leaseda479c52012-10-15 15:24:16 -0700704 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700705 * Returns the resolution level allowed to the given PID/UID pair.
706 *
707 * @param pid the PID
708 * @param uid the UID
709 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700710 */
Victoria Lease37425c32012-10-16 16:08:48 -0700711 private int getAllowedResolutionLevel(int pid, int uid) {
712 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
713 pid, uid) == PackageManager.PERMISSION_GRANTED) {
714 return RESOLUTION_LEVEL_FINE;
715 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
716 pid, uid) == PackageManager.PERMISSION_GRANTED) {
717 return RESOLUTION_LEVEL_COARSE;
718 } else {
719 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700720 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700721 }
722
723 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700724 * Returns the resolution level allowed to the caller
725 *
726 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700727 */
Victoria Lease37425c32012-10-16 16:08:48 -0700728 private int getCallerAllowedResolutionLevel() {
729 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
730 }
731
732 /**
733 * Throw SecurityException if specified resolution level is insufficient to use geofences.
734 *
735 * @param allowedResolutionLevel resolution level allowed to caller
736 */
737 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
738 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700739 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
740 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 }
742
Victoria Lease37425c32012-10-16 16:08:48 -0700743 /**
744 * Return the minimum resolution level required to use the specified location provider.
745 *
746 * @param provider the name of the location provider
747 * @return minimum resolution level required for provider
748 */
749 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700750 if (LocationManager.GPS_PROVIDER.equals(provider) ||
751 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
752 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700753 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700754 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
755 LocationManager.FUSED_PROVIDER.equals(provider)) {
756 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700757 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700758 } else {
759 // mock providers
760 LocationProviderInterface lp = mMockProviders.get(provider);
761 if (lp != null) {
762 ProviderProperties properties = lp.getProperties();
763 if (properties != null) {
764 if (properties.mRequiresSatellite) {
765 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700766 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700767 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
768 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700769 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700770 }
771 }
772 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700773 }
Victoria Lease37425c32012-10-16 16:08:48 -0700774 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700775 }
776
Victoria Lease37425c32012-10-16 16:08:48 -0700777 /**
778 * Throw SecurityException if specified resolution level is insufficient to use the named
779 * location provider.
780 *
781 * @param allowedResolutionLevel resolution level allowed to caller
782 * @param providerName the name of the location provider
783 */
784 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
785 String providerName) {
786 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
787 if (allowedResolutionLevel < requiredResolutionLevel) {
788 switch (requiredResolutionLevel) {
789 case RESOLUTION_LEVEL_FINE:
790 throw new SecurityException("\"" + providerName + "\" location provider " +
791 "requires ACCESS_FINE_LOCATION permission.");
792 case RESOLUTION_LEVEL_COARSE:
793 throw new SecurityException("\"" + providerName + "\" location provider " +
794 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
795 default:
796 throw new SecurityException("Insufficient permission for \"" + providerName +
797 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700798 }
799 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700800 }
801
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800802 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800803 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
804 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800805 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800806 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800807 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -0800808 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800809 }
810 return -1;
811 }
812
813 boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
814 int op = resolutionLevelToOp(allowedResolutionLevel);
815 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800816 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
817 return false;
818 }
819 }
820 return true;
821 }
822
823 boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -0800824 int op = resolutionLevelToOp(allowedResolutionLevel);
825 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -0800826 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
827 return false;
828 }
829 }
830 return true;
831 }
832
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700833 /**
834 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700835 * fused, also including ones that are not permitted to
836 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700837 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700838 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700840 ArrayList<String> out;
841 synchronized (mLock) {
842 out = new ArrayList<String>(mProviders.size());
843 for (LocationProviderInterface provider : mProviders) {
844 String name = provider.getName();
845 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700846 continue;
847 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 out.add(name);
849 }
850 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700851
852 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 return out;
854 }
855
Mike Lockwood03ca2162010-04-01 08:10:09 -0700856 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700857 * Return all providers by name, that match criteria and are optionally
858 * enabled.
859 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700860 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700861 @Override
862 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700863 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700864 ArrayList<String> out;
Victoria Lease269518e2012-10-29 08:25:39 -0700865 int callingUserId = UserHandle.getCallingUserId();
866 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -0700867 try {
868 synchronized (mLock) {
869 out = new ArrayList<String>(mProviders.size());
870 for (LocationProviderInterface provider : mProviders) {
871 String name = provider.getName();
872 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700873 continue;
874 }
Victoria Lease37425c32012-10-16 16:08:48 -0700875 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease269518e2012-10-29 08:25:39 -0700876 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700877 continue;
878 }
879 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
880 name, provider.getProperties(), criteria)) {
881 continue;
882 }
883 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700884 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700885 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700886 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700887 } finally {
888 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700889 }
890
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700891 if (D) Log.d(TAG, "getProviders()=" + out);
892 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700893 }
894
895 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700896 * Return the name of the best provider given a Criteria object.
897 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700898 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700899 * has been deprecated as well. So this method now uses
900 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700901 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700902 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700903 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700904 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700905
906 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700907 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700908 result = pickBest(providers);
909 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
910 return result;
911 }
912 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700913 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700914 result = pickBest(providers);
915 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
916 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700917 }
918
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700919 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700920 return null;
921 }
922
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700923 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700924 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700925 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700926 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
927 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700928 } else {
929 return providers.get(0);
930 }
931 }
932
Nick Pellye0fd6932012-07-11 10:26:13 -0700933 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700934 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
935 LocationProviderInterface p = mProvidersByName.get(provider);
936 if (p == null) {
937 throw new IllegalArgumentException("provider=" + provider);
938 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700939
940 boolean result = LocationProvider.propertiesMeetCriteria(
941 p.getName(), p.getProperties(), criteria);
942 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
943 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700944 }
945
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700947 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400948 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500949 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 boolean isEnabled = p.isEnabled();
951 String name = p.getName();
Victoria Lease269518e2012-10-29 08:25:39 -0700952 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700954 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700955 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700957 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700958 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700960 }
961 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700962 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
963 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 }
965 }
966
Victoria Leaseb711d572012-10-02 13:14:11 -0700967 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 int listeners = 0;
969
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500970 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700971 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972
973 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
976 if (records != null) {
977 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700978 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 UpdateRecord record = records.get(i);
Victoria Lease269518e2012-10-29 08:25:39 -0700980 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700981 // Sends a notification message to the receiver
982 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
983 if (deadReceivers == null) {
984 deadReceivers = new ArrayList<Receiver>();
985 }
986 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700988 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 }
991 }
992
993 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700994 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 removeUpdatesLocked(deadReceivers.get(i));
996 }
997 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700998
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 if (enabled) {
1000 p.enable();
1001 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001002 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 }
1004 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
1008
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001009 private void applyRequirementsLocked(String provider) {
1010 LocationProviderInterface p = mProvidersByName.get(provider);
1011 if (p == null) return;
1012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001014 WorkSource worksource = new WorkSource();
1015 ProviderRequest providerRequest = new ProviderRequest();
1016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001018 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001019 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001020 if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
1021 record.mReceiver.mAllowedResolutionLevel)) {
1022 LocationRequest locationRequest = record.mRequest;
1023 providerRequest.locationRequests.add(locationRequest);
1024 if (locationRequest.getInterval() < providerRequest.interval) {
1025 providerRequest.reportLocation = true;
1026 providerRequest.interval = locationRequest.getInterval();
1027 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001028 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001029 }
1030 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001031
1032 if (providerRequest.reportLocation) {
1033 // calculate who to blame for power
1034 // This is somewhat arbitrary. We pick a threshold interval
1035 // that is slightly higher that the minimum interval, and
1036 // spread the blame across all applications with a request
1037 // under that threshold.
1038 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1039 for (UpdateRecord record : records) {
Victoria Lease269518e2012-10-29 08:25:39 -07001040 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001041 LocationRequest locationRequest = record.mRequest;
1042 if (locationRequest.getInterval() <= thresholdInterval) {
Dianne Hackborn002a54e2013-01-10 17:34:55 -08001043 worksource.add(record.mReceiver.mUid, record.mReceiver.mPackageName);
Victoria Leaseb711d572012-10-02 13:14:11 -07001044 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001045 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001046 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 }
1048 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001049
1050 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1051 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 }
1053
1054 private class UpdateRecord {
1055 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001056 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001058 Location mLastFixBroadcast;
1059 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060
1061 /**
1062 * Note: must be constructed with lock held.
1063 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001064 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001066 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068
1069 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1070 if (records == null) {
1071 records = new ArrayList<UpdateRecord>();
1072 mRecordsByProvider.put(provider, records);
1073 }
1074 if (!records.contains(this)) {
1075 records.add(this);
1076 }
1077 }
1078
1079 /**
1080 * Method to be called when a record will no longer be used. Calling this multiple times
1081 * must have the same effect as calling it once.
1082 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001083 void disposeLocked(boolean removeReceiver) {
1084 // remove from mRecordsByProvider
1085 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1086 if (globalRecords != null) {
1087 globalRecords.remove(this);
1088 }
1089
1090 if (!removeReceiver) return; // the caller will handle the rest
1091
1092 // remove from Receiver#mUpdateRecords
1093 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1094 if (receiverRecords != null) {
1095 receiverRecords.remove(this.mProvider);
1096
1097 // and also remove the Receiver if it has no more update records
1098 if (removeReceiver && receiverRecords.size() == 0) {
1099 removeUpdatesLocked(mReceiver);
1100 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001101 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 }
1103
1104 @Override
1105 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001106 StringBuilder s = new StringBuilder();
1107 s.append("UpdateRecord[");
1108 s.append(mProvider);
1109 s.append(' ').append(mReceiver.mPackageName).append('(');
1110 s.append(mReceiver.mUid).append(')');
1111 s.append(' ').append(mRequest);
1112 s.append(']');
1113 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 }
1116
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001117 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001118 IBinder binder = listener.asBinder();
1119 Receiver receiver = mReceivers.get(binder);
1120 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001121 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001122 mReceivers.put(binder, receiver);
1123
1124 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001125 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001126 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001127 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001128 return null;
1129 }
1130 }
1131 return receiver;
1132 }
1133
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001134 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001135 Receiver receiver = mReceivers.get(intent);
1136 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001137 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001138 mReceivers.put(intent, receiver);
1139 }
1140 return receiver;
1141 }
1142
Victoria Lease37425c32012-10-16 16:08:48 -07001143 /**
1144 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1145 * and consistency requirements.
1146 *
1147 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001148 * @return a version of request that meets the given resolution and consistency requirements
1149 * @hide
1150 */
1151 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1152 LocationRequest sanitizedRequest = new LocationRequest(request);
1153 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1154 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001155 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001156 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001157 break;
1158 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001159 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001160 break;
1161 }
1162 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001163 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1164 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001165 }
Victoria Lease37425c32012-10-16 16:08:48 -07001166 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1167 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001168 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001169 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001170 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001171 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001172 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001173 }
Victoria Lease37425c32012-10-16 16:08:48 -07001174 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001175 }
1176
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001177 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001178 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001179 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001180 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001181 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001182 String[] packages = mPackageManager.getPackagesForUid(uid);
1183 if (packages == null) {
1184 throw new SecurityException("invalid UID " + uid);
1185 }
1186 for (String pkg : packages) {
1187 if (packageName.equals(pkg)) return;
1188 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001189 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001190 }
1191
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001192 private void checkPendingIntent(PendingIntent intent) {
1193 if (intent == null) {
1194 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001195 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001196 }
1197
1198 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1199 int pid, int uid, String packageName) {
1200 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001201 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001202 } else if (intent != null && listener != null) {
1203 throw new IllegalArgumentException("cannot register both listener and intent");
1204 } else if (intent != null) {
1205 checkPendingIntent(intent);
1206 return getReceiver(intent, pid, uid, packageName);
1207 } else {
1208 return getReceiver(listener, pid, uid, packageName);
1209 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001210 }
1211
Nick Pellye0fd6932012-07-11 10:26:13 -07001212 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001213 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1214 PendingIntent intent, String packageName) {
1215 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1216 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001217 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1218 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1219 request.getProvider());
1220 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 final int pid = Binder.getCallingPid();
1223 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001224 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 long identity = Binder.clearCallingIdentity();
1226 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001227 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1228 // a location.
Dianne Hackborn35654b62013-01-14 17:38:02 -08001229 checkLocationAccess(uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001230 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1231
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001232 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001233 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 } finally {
1236 Binder.restoreCallingIdentity(identity);
1237 }
1238 }
1239
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001240 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1241 int pid, int uid, String packageName) {
1242 // Figure out the provider. Either its explicitly request (legacy use cases), or
1243 // use the fused provider
1244 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1245 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001246 if (name == null) {
1247 throw new IllegalArgumentException("provider name must not be null");
1248 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001249 LocationProviderInterface provider = mProvidersByName.get(name);
1250 if (provider == null) {
1251 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1252 }
1253
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001254 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1255 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001256
1257 UpdateRecord record = new UpdateRecord(name, request, receiver);
1258 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1259 if (oldRecord != null) {
1260 oldRecord.disposeLocked(false);
1261 }
1262
Victoria Lease269518e2012-10-29 08:25:39 -07001263 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001264 if (isProviderEnabled) {
1265 applyRequirementsLocked(name);
1266 } else {
1267 // Notify the listener that updates are currently disabled
1268 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 }
1270 }
1271
Nick Pellye0fd6932012-07-11 10:26:13 -07001272 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001273 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1274 String packageName) {
1275 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001276
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001277 final int pid = Binder.getCallingPid();
1278 final int uid = Binder.getCallingUid();
1279 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1280
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001281 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001282 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001284 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001285 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001287 } finally {
1288 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 }
1290 }
1291
1292 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001293 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001294
1295 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1296 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1297 synchronized (receiver) {
1298 if (receiver.mPendingBroadcasts > 0) {
1299 decrementPendingBroadcasts();
1300 receiver.mPendingBroadcasts = 0;
1301 }
1302 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 }
1304
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001305 // Record which providers were associated with this listener
1306 HashSet<String> providers = new HashSet<String>();
1307 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1308 if (oldRecords != null) {
1309 // Call dispose() on the obsolete update records.
1310 for (UpdateRecord record : oldRecords.values()) {
1311 record.disposeLocked(false);
1312 }
1313 // Accumulate providers
1314 providers.addAll(oldRecords.keySet());
1315 }
1316
1317 // update provider
1318 for (String provider : providers) {
1319 // If provider is already disabled, don't need to do anything
Victoria Lease269518e2012-10-29 08:25:39 -07001320 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001321 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 }
1323
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 }
1326 }
1327
Nick Pellye0fd6932012-07-11 10:26:13 -07001328 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001329 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001330 if (D) Log.d(TAG, "getLastLocation: " + request);
1331 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001332 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001333 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001334 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1335 request.getProvider());
1336 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001337
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001338 final int uid = Binder.getCallingUid();
1339 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001340 try {
1341 if (mBlacklist.isBlacklisted(packageName)) {
1342 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1343 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001344 return null;
1345 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001346
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001347 if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
1348 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1349 packageName);
1350 return null;
1351 }
1352
Victoria Leaseb711d572012-10-02 13:14:11 -07001353 synchronized (mLock) {
1354 // Figure out the provider. Either its explicitly request (deprecated API's),
1355 // or use the fused provider
1356 String name = request.getProvider();
1357 if (name == null) name = LocationManager.FUSED_PROVIDER;
1358 LocationProviderInterface provider = mProvidersByName.get(name);
1359 if (provider == null) return null;
1360
Victoria Lease269518e2012-10-29 08:25:39 -07001361 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001362
1363 Location location = mLastLocation.get(name);
1364 if (location == null) {
1365 return null;
1366 }
Victoria Lease37425c32012-10-16 16:08:48 -07001367 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001368 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1369 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001370 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001371 }
Victoria Lease37425c32012-10-16 16:08:48 -07001372 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001373 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001374 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001375 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001376 return null;
1377 } finally {
1378 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001379 }
1380 }
1381
1382 @Override
1383 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1384 String packageName) {
1385 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001386 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1387 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001388 checkPendingIntent(intent);
1389 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001390 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1391 request.getProvider());
1392 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001393
Victoria Lease37425c32012-10-16 16:08:48 -07001394 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001395
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001396 // geo-fence manager uses the public location API, need to clear identity
1397 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001398 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1399 // temporary measure until geofences work for secondary users
1400 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1401 return;
1402 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001403 long identity = Binder.clearCallingIdentity();
1404 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001405 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1406 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001407 } finally {
1408 Binder.restoreCallingIdentity(identity);
1409 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001410 }
1411
1412 @Override
1413 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001414 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001415 checkPendingIntent(intent);
1416 checkPackageName(packageName);
1417
1418 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1419
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001420 // geo-fence manager uses the public location API, need to clear identity
1421 long identity = Binder.clearCallingIdentity();
1422 try {
1423 mGeofenceManager.removeFence(geofence, intent);
1424 } finally {
1425 Binder.restoreCallingIdentity(identity);
1426 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001427 }
1428
1429
1430 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001431 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001432 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 return false;
1434 }
Dianne Hackborn35654b62013-01-14 17:38:02 -08001435 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1436 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001437 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001439 final int uid = Binder.getCallingUid();
1440 final long ident = Binder.clearCallingIdentity();
1441 try {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001442 if (checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001443 return false;
1444 }
1445 } finally {
1446 Binder.restoreCallingIdentity(ident);
1447 }
1448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001450 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001452 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 return false;
1454 }
1455 return true;
1456 }
1457
Nick Pellye0fd6932012-07-11 10:26:13 -07001458 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001460 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001461 try {
1462 mGpsStatusProvider.removeGpsStatusListener(listener);
1463 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001464 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001465 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 }
1467 }
1468
Nick Pellye0fd6932012-07-11 10:26:13 -07001469 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001471 if (provider == null) {
1472 // throw NullPointerException to remain compatible with previous implementation
1473 throw new NullPointerException();
1474 }
Victoria Lease37425c32012-10-16 16:08:48 -07001475 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1476 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001479 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 != PackageManager.PERMISSION_GRANTED)) {
1481 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1482 }
1483
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001484 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001485 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001486 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001487
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001488 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 }
1490 }
1491
Nick Pellye0fd6932012-07-11 10:26:13 -07001492 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001493 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001494 if (Binder.getCallingUid() != Process.myUid()) {
1495 throw new SecurityException(
1496 "calling sendNiResponse from outside of the system is not allowed");
1497 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001498 try {
1499 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001500 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001501 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001502 return false;
1503 }
1504 }
1505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001507 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001508 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 * accessed by the caller
1510 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001511 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001512 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001513 if (mProvidersByName.get(provider) == null) {
1514 return null;
1515 }
1516
Victoria Lease37425c32012-10-16 16:08:48 -07001517 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1518 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001520 LocationProviderInterface p;
1521 synchronized (mLock) {
1522 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 }
1524
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001525 if (p == null) return null;
1526 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 }
1528
Nick Pellye0fd6932012-07-11 10:26:13 -07001529 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001531 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1532 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001533 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1534
Victoria Lease269518e2012-10-29 08:25:39 -07001535 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001536 try {
1537 synchronized (mLock) {
1538 LocationProviderInterface p = mProvidersByName.get(provider);
1539 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001540
Victoria Lease269518e2012-10-29 08:25:39 -07001541 return isAllowedBySettingsLocked(provider, mCurrentUserId);
Victoria Leaseb711d572012-10-02 13:14:11 -07001542 }
1543 } finally {
1544 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001545 }
1546 }
1547
1548 private void checkCallerIsProvider() {
1549 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1550 == PackageManager.PERMISSION_GRANTED) {
1551 return;
1552 }
1553
1554 // Previously we only used the INSTALL_LOCATION_PROVIDER
1555 // check. But that is system or signature
1556 // protection level which is not flexible enough for
1557 // providers installed oustide the system image. So
1558 // also allow providers with a UID matching the
1559 // currently bound package name
1560
1561 int uid = Binder.getCallingUid();
1562
1563 if (mGeocodeProvider != null) {
1564 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1565 }
1566 for (LocationProviderProxy proxy : mProxyProviders) {
1567 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1568 }
1569 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1570 "or UID of a currently bound location provider");
1571 }
1572
1573 private boolean doesPackageHaveUid(int uid, String packageName) {
1574 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 return false;
1576 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001577 try {
1578 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1579 if (appInfo.uid != uid) {
1580 return false;
1581 }
1582 } catch (NameNotFoundException e) {
1583 return false;
1584 }
1585 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 }
1587
Nick Pellye0fd6932012-07-11 10:26:13 -07001588 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001589 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001590 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001591
Nick Pelly2eeeec22012-07-18 13:13:37 -07001592 if (!location.isComplete()) {
1593 Log.w(TAG, "Dropping incomplete location: " + location);
1594 return;
1595 }
1596
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001597 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1598 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001599 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001600 mLocationHandler.sendMessageAtFrontOfQueue(m);
1601 }
1602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603
Laurent Tu75defb62012-11-01 16:21:52 -07001604 private static boolean shouldBroadcastSafe(
1605 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 // Always broadcast the first update
1607 if (lastLoc == null) {
1608 return true;
1609 }
1610
Nick Pellyf1be6862012-05-15 10:53:42 -07001611 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001612 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001613 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001614 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 return false;
1616 }
1617
1618 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001619 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620 if (minDistance > 0.0) {
1621 if (loc.distanceTo(lastLoc) <= minDistance) {
1622 return false;
1623 }
1624 }
1625
Laurent Tu75defb62012-11-01 16:21:52 -07001626 // Check whether sufficient number of udpates is left
1627 if (record.mRequest.getNumUpdates() <= 0) {
1628 return false;
1629 }
1630
1631 // Check whether the expiry date has passed
1632 if (record.mRequest.getExpireAt() < now) {
1633 return false;
1634 }
1635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 return true;
1637 }
1638
Mike Lockwooda4903f22010-02-17 06:42:23 -05001639 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001640 if (D) Log.d(TAG, "incoming location: " + location);
1641
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001642 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001643 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644
Laurent Tu60ec50a2012-10-04 17:00:10 -07001645 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001646 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001647 if (p == null) return;
1648
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001649 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001650 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1651 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001652 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001653 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001654 lastLocation = new Location(provider);
1655 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001656 } else {
1657 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1658 if (noGPSLocation == null && lastNoGPSLocation != null) {
1659 // New location has no no-GPS location: adopt last no-GPS location. This is set
1660 // directly into location because we do not want to notify COARSE clients.
1661 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1662 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001663 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001664 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665
Laurent Tu60ec50a2012-10-04 17:00:10 -07001666 // Skip if there are no UpdateRecords for this provider.
1667 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1668 if (records == null || records.size() == 0) return;
1669
Victoria Lease09016ab2012-09-16 12:33:15 -07001670 // Fetch coarse location
1671 Location coarseLocation = null;
1672 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1673 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1674 }
1675
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 // Fetch latest status update time
1677 long newStatusUpdateTime = p.getStatusUpdateTime();
1678
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001679 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 Bundle extras = new Bundle();
1681 int status = p.getStatus(extras);
1682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001684 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001687 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001689 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001690
Victoria Lease269518e2012-10-29 08:25:39 -07001691 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1692 if (receiverUserId != mCurrentUserId) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001693 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07001694 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07001695 " (current user: " + mCurrentUserId + ", app: " +
1696 receiver.mPackageName + ")");
1697 }
1698 continue;
1699 }
1700
Nick Pelly4035f5a2012-08-17 14:43:49 -07001701 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1702 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1703 receiver.mPackageName);
1704 continue;
1705 }
1706
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001707 if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
1708 receiver.mAllowedResolutionLevel)) {
1709 if (D) Log.d(TAG, "skipping loc update for no op app: " +
1710 receiver.mPackageName);
1711 continue;
1712 }
1713
Victoria Lease09016ab2012-09-16 12:33:15 -07001714 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001715 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1716 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001717 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001718 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001719 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001720 if (notifyLocation != null) {
1721 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07001722 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001723 if (lastLoc == null) {
1724 lastLoc = new Location(notifyLocation);
1725 r.mLastFixBroadcast = lastLoc;
1726 } else {
1727 lastLoc.set(notifyLocation);
1728 }
1729 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1730 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1731 receiverDead = true;
1732 }
Laurent Tu75defb62012-11-01 16:21:52 -07001733 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 }
1735 }
1736
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001737 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001739 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001741 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001743 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001744 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001745 }
1746 }
1747
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001748 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07001749 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001750 if (deadUpdateRecords == null) {
1751 deadUpdateRecords = new ArrayList<UpdateRecord>();
1752 }
1753 deadUpdateRecords.add(r);
1754 }
1755 // track dead receivers
1756 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001757 if (deadReceivers == null) {
1758 deadReceivers = new ArrayList<Receiver>();
1759 }
1760 if (!deadReceivers.contains(receiver)) {
1761 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 }
1763 }
1764 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001765
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001766 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001768 for (Receiver receiver : deadReceivers) {
1769 removeUpdatesLocked(receiver);
1770 }
1771 }
1772 if (deadUpdateRecords != null) {
1773 for (UpdateRecord r : deadUpdateRecords) {
1774 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 }
Victoria Lease8b38b292012-12-04 15:04:43 -08001776 applyRequirementsLocked(provider);
1777 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 }
1779
1780 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08001781 public LocationWorkerHandler(Looper looper) {
1782 super(looper, null, true);
1783 }
1784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001785 @Override
1786 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001787 switch (msg.what) {
1788 case MSG_LOCATION_CHANGED:
1789 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1790 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 }
1792 }
1793 }
1794
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001795 private boolean isMockProvider(String provider) {
1796 synchronized (mLock) {
1797 return mMockProviders.containsKey(provider);
1798 }
1799 }
1800
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001801 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001802 // create a working copy of the incoming Location so that the service can modify it without
1803 // disturbing the caller's copy
1804 Location myLocation = new Location(location);
1805 String provider = myLocation.getProvider();
1806
1807 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
1808 // bit if location did not come from a mock provider because passive/fused providers can
1809 // forward locations from mock providers, and should not grant them legitimacy in doing so.
1810 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
1811 myLocation.setIsFromMockProvider(true);
1812 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08001813
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001814 if (!passive) {
1815 // notify passive provider of the new location
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001816 mPassiveProvider.updateLocation(myLocation);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001817 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001819 synchronized (mLock) {
Victoria Lease269518e2012-10-29 08:25:39 -07001820 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08001821 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001824 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825
Mike Lockwoode97ae402010-09-29 15:23:46 -04001826 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1827 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001828 public void onPackageDisappeared(String packageName, int reason) {
1829 // remove all receivers associated with this package name
1830 synchronized (mLock) {
1831 ArrayList<Receiver> deadReceivers = null;
1832
1833 for (Receiver receiver : mReceivers.values()) {
1834 if (receiver.mPackageName.equals(packageName)) {
1835 if (deadReceivers == null) {
1836 deadReceivers = new ArrayList<Receiver>();
1837 }
1838 deadReceivers.add(receiver);
1839 }
1840 }
1841
1842 // perform removal outside of mReceivers loop
1843 if (deadReceivers != null) {
1844 for (Receiver receiver : deadReceivers) {
1845 removeUpdatesLocked(receiver);
1846 }
1847 }
1848 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001849 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001850 };
1851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 // Wake locks
1853
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001854 private void incrementPendingBroadcasts() {
1855 synchronized (mWakeLock) {
1856 if (mPendingBroadcasts++ == 0) {
1857 try {
1858 mWakeLock.acquire();
1859 log("Acquired wakelock");
1860 } catch (Exception e) {
1861 // This is to catch a runtime exception thrown when we try to release an
1862 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001863 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001864 }
1865 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001866 }
1867 }
1868
1869 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001870 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001871 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001872 try {
1873 // Release wake lock
1874 if (mWakeLock.isHeld()) {
1875 mWakeLock.release();
1876 log("Released wakelock");
1877 } else {
1878 log("Can't release wakelock again!");
1879 }
1880 } catch (Exception e) {
1881 // This is to catch a runtime exception thrown when we try to release an
1882 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001883 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001884 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001885 }
1886 }
1887 }
1888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889 // Geocoder
1890
Nick Pellye0fd6932012-07-11 10:26:13 -07001891 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001892 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001893 return mGeocodeProvider != null;
1894 }
1895
Nick Pellye0fd6932012-07-11 10:26:13 -07001896 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001898 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001899 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001900 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1901 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001903 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 }
1905
Mike Lockwooda55c3212009-04-15 11:10:11 -04001906
Nick Pellye0fd6932012-07-11 10:26:13 -07001907 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001909 double lowerLeftLatitude, double lowerLeftLongitude,
1910 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001911 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001912
1913 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001914 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1915 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1916 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001918 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001919 }
1920
1921 // Mock Providers
1922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 private void checkMockPermissionsSafe() {
1924 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1925 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1926 if (!allowMocks) {
1927 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1928 }
1929
1930 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1931 PackageManager.PERMISSION_GRANTED) {
1932 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001933 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001934 }
1935
Nick Pellye0fd6932012-07-11 10:26:13 -07001936 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001937 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 checkMockPermissionsSafe();
1939
Mike Lockwooda4903f22010-02-17 06:42:23 -05001940 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1941 throw new IllegalArgumentException("Cannot mock the passive location provider");
1942 }
1943
Mike Lockwood86328a92009-10-23 08:38:25 -04001944 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001945 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001946 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001947 // remove the real provider if we are replacing GPS or network provider
1948 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001949 || LocationManager.NETWORK_PROVIDER.equals(name)
1950 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001951 LocationProviderInterface p = mProvidersByName.get(name);
1952 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001953 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001954 }
1955 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001956 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1958 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001959 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001960 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001961 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962 updateProvidersLocked();
1963 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001964 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 }
1966
Nick Pellye0fd6932012-07-11 10:26:13 -07001967 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 public void removeTestProvider(String provider) {
1969 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001970 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09001971 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001972 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1974 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001975 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001976 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001977
1978 // reinstate real provider if available
1979 LocationProviderInterface realProvider = mRealProviders.get(provider);
1980 if (realProvider != null) {
1981 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001982 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001983 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001985 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 }
1987 }
1988
Nick Pellye0fd6932012-07-11 10:26:13 -07001989 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 public void setTestProviderLocation(String provider, Location loc) {
1991 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001992 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001993 MockProvider mockProvider = mMockProviders.get(provider);
1994 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001995 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1996 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001997 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1998 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001999 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002000 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002001 }
2002 }
2003
Nick Pellye0fd6932012-07-11 10:26:13 -07002004 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 public void clearTestProviderLocation(String provider) {
2006 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002007 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002008 MockProvider mockProvider = mMockProviders.get(provider);
2009 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002010 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2011 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002012 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 }
2014 }
2015
Nick Pellye0fd6932012-07-11 10:26:13 -07002016 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002017 public void setTestProviderEnabled(String provider, boolean enabled) {
2018 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002019 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002020 MockProvider mockProvider = mMockProviders.get(provider);
2021 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2023 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002024 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002026 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002027 mEnabledProviders.add(provider);
2028 mDisabledProviders.remove(provider);
2029 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002030 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 mEnabledProviders.remove(provider);
2032 mDisabledProviders.add(provider);
2033 }
2034 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002035 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 }
2037 }
2038
Nick Pellye0fd6932012-07-11 10:26:13 -07002039 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 public void clearTestProviderEnabled(String provider) {
2041 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002042 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002043 MockProvider mockProvider = mMockProviders.get(provider);
2044 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2046 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002047 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 mEnabledProviders.remove(provider);
2049 mDisabledProviders.remove(provider);
2050 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002051 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 }
2053 }
2054
Nick Pellye0fd6932012-07-11 10:26:13 -07002055 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2057 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002058 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002059 MockProvider mockProvider = mMockProviders.get(provider);
2060 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2062 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002063 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002064 }
2065 }
2066
Nick Pellye0fd6932012-07-11 10:26:13 -07002067 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002068 public void clearTestProviderStatus(String provider) {
2069 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002070 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002071 MockProvider mockProvider = mMockProviders.get(provider);
2072 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2074 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002075 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002076 }
2077 }
2078
2079 private void log(String log) {
2080 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002081 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002082 }
2083 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002084
2085 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002086 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2087 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2088 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002089 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002090 + Binder.getCallingPid()
2091 + ", uid=" + Binder.getCallingUid());
2092 return;
2093 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002094
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002095 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002096 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002097 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002098 for (Receiver receiver : mReceivers.values()) {
2099 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002101 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002102 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2103 pw.println(" " + entry.getKey() + ":");
2104 for (UpdateRecord record : entry.getValue()) {
2105 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002106 }
2107 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002109 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2110 String provider = entry.getKey();
2111 Location location = entry.getValue();
2112 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002113 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002114
Nick Pellye0fd6932012-07-11 10:26:13 -07002115 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 if (mEnabledProviders.size() > 0) {
2118 pw.println(" Enabled Providers:");
2119 for (String i : mEnabledProviders) {
2120 pw.println(" " + i);
2121 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002123 }
2124 if (mDisabledProviders.size() > 0) {
2125 pw.println(" Disabled Providers:");
2126 for (String i : mDisabledProviders) {
2127 pw.println(" " + i);
2128 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002129 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002130 pw.append(" ");
2131 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 if (mMockProviders.size() > 0) {
2133 pw.println(" Mock Providers:");
2134 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002135 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002136 }
2137 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002138
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002139 pw.append(" fudger: ");
2140 mLocationFudger.dump(fd, pw, args);
2141
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002142 if (args.length > 0 && "short".equals(args[0])) {
2143 return;
2144 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002145 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002146 pw.print(provider.getName() + " Internal State");
2147 if (provider instanceof LocationProviderProxy) {
2148 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2149 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002150 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002151 pw.println(":");
2152 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002153 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002154 }
2155 }
2156}