blob: b834a8484f693a19674c84f4a25dd2035759fb69 [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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.PendingIntent;
Mike Lockwood9637d472009-04-02 21:41:57 -070020import android.content.ContentQueryMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070027import android.content.pm.PackageManager.NameNotFoundException;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050028import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070029import android.database.ContentObserver;
Mike Lockwood9637d472009-04-02 21:41:57 -070030import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070032import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050033import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070034import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040036import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.location.ILocationListener;
38import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040039import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.location.Location;
41import android.location.LocationManager;
42import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070043import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.net.ConnectivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.Binder;
46import android.os.Bundle;
47import android.os.Handler;
48import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070049import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.Message;
51import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070052import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070054import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070055import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070056import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.provider.Settings;
Nick Pellye0fd6932012-07-11 10:26:13 -070058import android.provider.Settings.NameValueTable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080060import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
Mike Lockwoode97ae402010-09-29 15:23:46 -040062import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070063import com.android.internal.location.ProviderProperties;
64import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040065import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070066import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040067import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070068import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070069import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040070import com.android.server.location.LocationProviderInterface;
71import com.android.server.location.LocationProviderProxy;
72import com.android.server.location.MockProvider;
73import com.android.server.location.PassiveProvider;
74
75import java.io.FileDescriptor;
76import java.io.PrintWriter;
77import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070078import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040079import java.util.HashMap;
80import java.util.HashSet;
81import java.util.List;
82import java.util.Map;
83import java.util.Observable;
84import java.util.Observer;
85import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
87/**
88 * The service class that manages LocationProviders and issues location
89 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 */
Brian Muramatsubb95cb92012-08-29 10:43:21 -070091public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070093 public static final boolean D = false;
94
95 private static final String WAKELOCK_KEY = TAG;
96 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 private static final String ACCESS_FINE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070099 android.Manifest.permission.ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private static final String ACCESS_COARSE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700101 android.Manifest.permission.ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700103 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700105 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400106 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700107 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
108
109 private static final String NETWORK_LOCATION_SERVICE_ACTION =
110 "com.android.location.service.v2.NetworkLocationProvider";
111 private static final String FUSED_LOCATION_SERVICE_ACTION =
112 "com.android.location.service.FusedLocationProvider";
113
114 private static final int MSG_LOCATION_CHANGED = 1;
115
Nick Pellyf1be6862012-05-15 10:53:42 -0700116 // Location Providers may sometimes deliver location updates
117 // slightly faster that requested - provide grace period so
118 // we don't unnecessarily filter events that are otherwise on
119 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700120 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700121
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700122 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
123
124 private final Context mContext;
125
126 // used internally for synchronization
127 private final Object mLock = new Object();
128
129 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700130 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700131 private GeofenceManager mGeofenceManager;
132 private PowerManager.WakeLock mWakeLock;
133 private PackageManager mPackageManager;
134 private GeocoderProxy mGeocodeProvider;
135 private IGpsStatusProvider mGpsStatusProvider;
136 private INetInitiatedListener mNetInitiatedListener;
137 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700138 private PassiveProvider mPassiveProvider; // track passive provider for special cases
139 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700140
141 // --- fields below are protected by mWakeLock ---
142 private int mPendingBroadcasts;
143
144 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 // Set of providers that are explicitly enabled
146 private final Set<String> mEnabledProviders = new HashSet<String>();
147
148 // Set of providers that are explicitly disabled
149 private final Set<String> mDisabledProviders = new HashSet<String>();
150
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700151 // Mock (test) providers
152 private final HashMap<String, MockProvider> mMockProviders =
153 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400156 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700158 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500159 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400161
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162 // real providers, saved here when mocked out
163 private final HashMap<String, LocationProviderInterface> mRealProviders =
164 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700166 // mapping from provider name to provider
167 private final HashMap<String, LocationProviderInterface> mProvidersByName =
168 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700170 // mapping from provider name to all its UpdateRecords
171 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
172 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700173
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174 // mapping from provider name to last known location
175 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 // all providers that operate over proxy, for authorizing incoming location
178 private final ArrayList<LocationProviderProxy> mProxyProviders =
179 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 public LocationManagerService(Context context) {
182 super();
183 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800184
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 if (D) Log.d(TAG, "Constructed");
186
187 // most startup is deferred until systemReady()
188 }
189
190 public void systemReady() {
191 Thread thread = new Thread(null, this, THREAD_NAME);
192 thread.start();
193 }
194
195 @Override
196 public void run() {
197 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
198 Looper.prepare();
199 mLocationHandler = new LocationWorkerHandler();
200 init();
201 Looper.loop();
202 }
203
204 private void init() {
205 if (D) Log.d(TAG, "init()");
206
207 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
208 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
209 mPackageManager = mContext.getPackageManager();
210
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700211 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
212 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700213 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700214
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700215 synchronized (mLock) {
216 loadProvidersLocked();
217 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700218
Nick Pelly4035f5a2012-08-17 14:43:49 -0700219 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700220
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700221 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700222 mContext.getContentResolver().registerContentObserver(
223 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
224 new ContentObserver(mLocationHandler) {
225 @Override
226 public void onChange(boolean selfChange) {
227 synchronized (mLock) {
228 updateProvidersLocked();
229 }
230 }
231 });
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700232 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700233
234 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700235 }
236
237 private void loadProvidersLocked() {
238 if (GpsLocationProvider.isSupported()) {
239 // Create a gps location provider
240 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
241 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
242 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
243 addProviderLocked(gpsProvider);
244 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
245 }
246
247 // create a passive location provider, which is always enabled
248 PassiveProvider passiveProvider = new PassiveProvider(this);
249 addProviderLocked(passiveProvider);
250 mEnabledProviders.add(passiveProvider.getName());
251 mPassiveProvider = passiveProvider;
252
253 /*
254 Load package name(s) containing location provider support.
255 These packages can contain services implementing location providers:
256 Geocoder Provider, Network Location Provider, and
257 Fused Location Provider. They will each be searched for
258 service components implementing these providers.
259 The location framework also has support for installation
260 of new location providers at run-time. The new package does not
261 have to be explicitly listed here, however it must have a signature
262 that matches the signature of at least one package on this list.
263 */
264 Resources resources = mContext.getResources();
265 ArrayList<String> providerPackageNames = new ArrayList<String>();
266 String[] pkgs1 = resources.getStringArray(
267 com.android.internal.R.array.config_locationProviderPackageNames);
268 String[] pkgs2 = resources.getStringArray(
269 com.android.internal.R.array.config_overlay_locationProviderPackageNames);
270 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
271 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
272 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
273 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
274
275 // bind to network provider
276 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
277 mContext,
278 LocationManager.NETWORK_PROVIDER,
279 NETWORK_LOCATION_SERVICE_ACTION,
280 providerPackageNames, mLocationHandler);
281 if (networkProvider != null) {
282 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
283 mProxyProviders.add(networkProvider);
284 addProviderLocked(networkProvider);
285 } else {
286 Slog.w(TAG, "no network location provider found");
287 }
288
289 // bind to fused provider
290 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
291 mContext,
292 LocationManager.FUSED_PROVIDER,
293 FUSED_LOCATION_SERVICE_ACTION,
294 providerPackageNames, mLocationHandler);
295 if (fusedLocationProvider != null) {
296 addProviderLocked(fusedLocationProvider);
297 mProxyProviders.add(fusedLocationProvider);
298 mEnabledProviders.add(fusedLocationProvider.getName());
299 } else {
300 Slog.e(TAG, "no fused location provider found",
301 new IllegalStateException("Location service needs a fused location provider"));
302 }
303
304 // bind to geocoder provider
305 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
306 if (mGeocodeProvider == null) {
307 Slog.e(TAG, "no geocoder provider found");
308 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700309 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 /**
312 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
313 * location updates.
314 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700315 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700316 final int mUid; // uid of receiver
317 final int mPid; // pid of receiver
318 final String mPackageName; // package name of receiver
319 final String mPermission; // best permission that receiver has
320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 final ILocationListener mListener;
322 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700324
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400325 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700326
Mike Lockwood48f17512009-04-23 09:12:08 -0700327 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700329 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
330 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700333 if (listener != null) {
334 mKey = listener.asBinder();
335 } else {
336 mKey = intent;
337 }
338 mPermission = checkPermission();
339 mUid = uid;
340 mPid = pid;
341 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 }
343
344 @Override
345 public boolean equals(Object otherObj) {
346 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700347 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 }
349 return false;
350 }
351
352 @Override
353 public int hashCode() {
354 return mKey.hashCode();
355 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 @Override
358 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700359 StringBuilder s = new StringBuilder();
360 s.append("Reciever[");
361 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700363 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700365 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700367 for (String p : mUpdateRecords.keySet()) {
368 s.append(" ").append(mUpdateRecords.get(p).toString());
369 }
370 s.append("]");
371 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 }
373
374 public boolean isListener() {
375 return mListener != null;
376 }
377
378 public boolean isPendingIntent() {
379 return mPendingIntent != null;
380 }
381
382 public ILocationListener getListener() {
383 if (mListener != null) {
384 return mListener;
385 }
386 throw new IllegalStateException("Request for non-existent listener");
387 }
388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
390 if (mListener != null) {
391 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700392 synchronized (this) {
393 // synchronize to ensure incrementPendingBroadcastsLocked()
394 // is called before decrementPendingBroadcasts()
395 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700396 // call this after broadcasting so we do not increment
397 // if we throw an exeption.
398 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700399 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 } catch (RemoteException e) {
401 return false;
402 }
403 } else {
404 Intent statusChanged = new Intent();
405 statusChanged.putExtras(extras);
406 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
407 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700408 synchronized (this) {
409 // synchronize to ensure incrementPendingBroadcastsLocked()
410 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700411 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700412 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700413 // call this after broadcasting so we do not increment
414 // if we throw an exeption.
415 incrementPendingBroadcastsLocked();
416 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 } catch (PendingIntent.CanceledException e) {
418 return false;
419 }
420 }
421 return true;
422 }
423
424 public boolean callLocationChangedLocked(Location location) {
425 if (mListener != null) {
426 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700427 synchronized (this) {
428 // synchronize to ensure incrementPendingBroadcastsLocked()
429 // is called before decrementPendingBroadcasts()
430 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700431 // call this after broadcasting so we do not increment
432 // if we throw an exeption.
433 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700434 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 } catch (RemoteException e) {
436 return false;
437 }
438 } else {
439 Intent locationChanged = new Intent();
440 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
441 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700442 synchronized (this) {
443 // synchronize to ensure incrementPendingBroadcastsLocked()
444 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700445 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700446 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700447 // call this after broadcasting so we do not increment
448 // if we throw an exeption.
449 incrementPendingBroadcastsLocked();
450 }
451 } catch (PendingIntent.CanceledException e) {
452 return false;
453 }
454 }
455 return true;
456 }
457
458 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
459 if (mListener != null) {
460 try {
461 synchronized (this) {
462 // synchronize to ensure incrementPendingBroadcastsLocked()
463 // is called before decrementPendingBroadcasts()
464 if (enabled) {
465 mListener.onProviderEnabled(provider);
466 } else {
467 mListener.onProviderDisabled(provider);
468 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700469 // call this after broadcasting so we do not increment
470 // if we throw an exeption.
471 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700472 }
473 } catch (RemoteException e) {
474 return false;
475 }
476 } else {
477 Intent providerIntent = new Intent();
478 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
479 try {
480 synchronized (this) {
481 // synchronize to ensure incrementPendingBroadcastsLocked()
482 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700483 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700484 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700485 // call this after broadcasting so we do not increment
486 // if we throw an exeption.
487 incrementPendingBroadcastsLocked();
488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 } catch (PendingIntent.CanceledException e) {
490 return false;
491 }
492 }
493 return true;
494 }
495
Nick Pellyf1be6862012-05-15 10:53:42 -0700496 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700498 if (D) Log.d(TAG, "Location listener died");
499
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400500 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 removeUpdatesLocked(this);
502 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700503 synchronized (this) {
504 if (mPendingBroadcasts > 0) {
505 LocationManagerService.this.decrementPendingBroadcasts();
506 mPendingBroadcasts = 0;
507 }
508 }
509 }
510
Nick Pellye0fd6932012-07-11 10:26:13 -0700511 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700512 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
513 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400514 synchronized (this) {
515 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700516 }
517 }
518
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400519 // this must be called while synchronized by caller in a synchronized block
520 // containing the sending of the broadcaset
521 private void incrementPendingBroadcastsLocked() {
522 if (mPendingBroadcasts++ == 0) {
523 LocationManagerService.this.incrementPendingBroadcasts();
524 }
525 }
526
527 private void decrementPendingBroadcastsLocked() {
528 if (--mPendingBroadcasts == 0) {
529 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700530 }
531 }
532 }
533
Nick Pellye0fd6932012-07-11 10:26:13 -0700534 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700535 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400536 //Do not use getReceiver here as that will add the ILocationListener to
537 //the receiver list if it is not found. If it is not found then the
538 //LocationListener was removed when it had a pending broadcast and should
539 //not be added back.
540 IBinder binder = listener.asBinder();
541 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700542 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400543 synchronized (receiver) {
544 // so wakelock calls will succeed
545 long identity = Binder.clearCallingIdentity();
546 receiver.decrementPendingBroadcastsLocked();
547 Binder.restoreCallingIdentity(identity);
548 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 }
550 }
551
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700552 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400553 mProviders.add(provider);
554 mProvidersByName.put(provider.getName(), provider);
555 }
556
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700557 private void removeProviderLocked(LocationProviderInterface provider) {
558 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400559 mProviders.remove(provider);
560 mProvidersByName.remove(provider.getName());
561 }
562
Mike Lockwood3d12b512009-04-21 23:25:35 -0700563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 private boolean isAllowedBySettingsLocked(String provider) {
565 if (mEnabledProviders.contains(provider)) {
566 return true;
567 }
568 if (mDisabledProviders.contains(provider)) {
569 return false;
570 }
571 // Use system settings
572 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573
Brad Larson8eb3ea62009-12-29 11:47:55 -0600574 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 }
576
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700577 /**
578 * Throw SecurityException if caller has neither COARSE or FINE.
579 * Otherwise, return the best permission.
580 */
581 private String checkPermission() {
582 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
583 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700584 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700585 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
586 PackageManager.PERMISSION_GRANTED) {
587 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700589
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700590 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
Victoria Lease4fab68b2012-09-13 13:20:59 -0700591 " ACCESS_FINE_LOCATION permission");
592 }
593
594 /**
595 * Throw SecurityException if caller lacks permission to use Geofences.
596 */
597 private void checkGeofencePermission() {
598 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
599 PackageManager.PERMISSION_GRANTED) {
600 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
601 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 }
603
Victoria Lease8dbb6342012-09-21 16:55:53 -0700604 private boolean isAllowedProviderSafe(String provider) {
605 if (LocationManager.GPS_PROVIDER.equals(provider) ||
606 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
607 // gps and passive providers require FINE permission
608 return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
609 == PackageManager.PERMISSION_GRANTED;
610 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
611 LocationManager.FUSED_PROVIDER.equals(provider)) {
612 // network and fused providers are ok with COARSE or FINE
613 return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
614 == PackageManager.PERMISSION_GRANTED) ||
615 (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
616 == PackageManager.PERMISSION_GRANTED);
617 }
618 return false;
619 }
620
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700621 /**
622 * Returns all providers by name, including passive, but excluding
623 * fused.
624 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700625 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700627 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700629 ArrayList<String> out;
630 synchronized (mLock) {
631 out = new ArrayList<String>(mProviders.size());
632 for (LocationProviderInterface provider : mProviders) {
633 String name = provider.getName();
634 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700635 continue;
636 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 out.add(name);
638 }
639 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700640
641 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 return out;
643 }
644
Mike Lockwood03ca2162010-04-01 08:10:09 -0700645 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700646 * Return all providers by name, that match criteria and are optionally
647 * enabled.
648 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700649 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700650 @Override
651 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700652 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700653 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700654 out = new ArrayList<String>(mProviders.size());
655 for (LocationProviderInterface provider : mProviders) {
656 String name = provider.getName();
657 if (LocationManager.FUSED_PROVIDER.equals(name)) {
658 continue;
659 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700660 if (isAllowedProviderSafe(name)) {
661 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
662 continue;
663 }
664 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
665 name, provider.getProperties(), criteria)) {
666 continue;
667 }
668 out.add(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700669 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700670 }
671 }
672
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700673 if (D) Log.d(TAG, "getProviders()=" + out);
674 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700675 }
676
677 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700678 * Return the name of the best provider given a Criteria object.
679 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700680 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700681 * has been deprecated as well. So this method now uses
682 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700683 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700684 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700685 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700686 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700687
688 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700689 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700690 result = pickBest(providers);
691 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
692 return result;
693 }
694 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700695 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700696 result = pickBest(providers);
697 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
698 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700699 }
700
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700701 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700702 return null;
703 }
704
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700705 private String pickBest(List<String> providers) {
706 if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
707 return LocationManager.NETWORK_PROVIDER;
708 } else if (providers.contains(LocationManager.GPS_PROVIDER)) {
709 return LocationManager.GPS_PROVIDER;
710 } else {
711 return providers.get(0);
712 }
713 }
714
Nick Pellye0fd6932012-07-11 10:26:13 -0700715 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700716 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700717 checkPermission();
718
Mike Lockwood03ca2162010-04-01 08:10:09 -0700719 LocationProviderInterface p = mProvidersByName.get(provider);
720 if (p == null) {
721 throw new IllegalArgumentException("provider=" + provider);
722 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700723
724 boolean result = LocationProvider.propertiesMeetCriteria(
725 p.getName(), p.getProperties(), criteria);
726 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
727 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700728 }
729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700731 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400732 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500733 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 boolean isEnabled = p.isEnabled();
735 String name = p.getName();
736 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 if (isEnabled && !shouldBeEnabled) {
738 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700739 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 } else if (!isEnabled && shouldBeEnabled) {
741 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700742 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700744 }
745 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700746 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
747 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 }
749 }
750
751 private void updateProviderListenersLocked(String provider, boolean enabled) {
752 int listeners = 0;
753
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500754 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700755 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756
757 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
760 if (records != null) {
761 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700762 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 UpdateRecord record = records.get(i);
764 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700765 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
766 if (deadReceivers == null) {
767 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 }
Simon Schoar46866572009-06-10 21:12:10 +0200769 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 }
771 listeners++;
772 }
773 }
774
775 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700776 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 removeUpdatesLocked(deadReceivers.get(i));
778 }
779 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 if (enabled) {
782 p.enable();
783 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700784 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 }
786 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 }
790
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700791 private void applyRequirementsLocked(String provider) {
792 LocationProviderInterface p = mProvidersByName.get(provider);
793 if (p == null) return;
794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700796 WorkSource worksource = new WorkSource();
797 ProviderRequest providerRequest = new ProviderRequest();
798
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700800 for (UpdateRecord record : records) {
801 LocationRequest locationRequest = record.mRequest;
802
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700803 providerRequest.locationRequests.add(locationRequest);
804 if (locationRequest.getInterval() < providerRequest.interval) {
805 providerRequest.reportLocation = true;
806 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700807 }
808 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700809
810 if (providerRequest.reportLocation) {
811 // calculate who to blame for power
812 // This is somewhat arbitrary. We pick a threshold interval
813 // that is slightly higher that the minimum interval, and
814 // spread the blame across all applications with a request
815 // under that threshold.
816 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
817 for (UpdateRecord record : records) {
818 LocationRequest locationRequest = record.mRequest;
819 if (locationRequest.getInterval() <= thresholdInterval) {
820 worksource.add(record.mReceiver.mUid);
821 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 }
824 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700825
826 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
827 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 }
829
830 private class UpdateRecord {
831 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700832 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400834 Location mLastFixBroadcast;
835 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836
837 /**
838 * Note: must be constructed with lock held.
839 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700840 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700842 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844
845 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
846 if (records == null) {
847 records = new ArrayList<UpdateRecord>();
848 mRecordsByProvider.put(provider, records);
849 }
850 if (!records.contains(this)) {
851 records.add(this);
852 }
853 }
854
855 /**
856 * Method to be called when a record will no longer be used. Calling this multiple times
857 * must have the same effect as calling it once.
858 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700859 void disposeLocked(boolean removeReceiver) {
860 // remove from mRecordsByProvider
861 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
862 if (globalRecords != null) {
863 globalRecords.remove(this);
864 }
865
866 if (!removeReceiver) return; // the caller will handle the rest
867
868 // remove from Receiver#mUpdateRecords
869 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
870 if (receiverRecords != null) {
871 receiverRecords.remove(this.mProvider);
872
873 // and also remove the Receiver if it has no more update records
874 if (removeReceiver && receiverRecords.size() == 0) {
875 removeUpdatesLocked(mReceiver);
876 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 }
879
880 @Override
881 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700882 StringBuilder s = new StringBuilder();
883 s.append("UpdateRecord[");
884 s.append(mProvider);
885 s.append(' ').append(mReceiver.mPackageName).append('(');
886 s.append(mReceiver.mUid).append(')');
887 s.append(' ').append(mRequest);
888 s.append(']');
889 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 }
892
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700893 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400894 IBinder binder = listener.asBinder();
895 Receiver receiver = mReceivers.get(binder);
896 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700897 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400898 mReceivers.put(binder, receiver);
899
900 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700901 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400902 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800903 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400904 return null;
905 }
906 }
907 return receiver;
908 }
909
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700910 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400911 Receiver receiver = mReceivers.get(intent);
912 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700913 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400914 mReceivers.put(intent, receiver);
915 }
916 return receiver;
917 }
918
Victoria Lease09016ab2012-09-16 12:33:15 -0700919 private boolean isProviderAllowedByCoarsePermission(String provider) {
920 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
921 return true;
922 }
923 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
924 return true;
925 }
926 if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
927 return true;
928 }
929 return false;
930 }
931
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700932 private String checkPermissionAndRequest(LocationRequest request) {
933 String perm = checkPermission();
934
935 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Victoria Lease09016ab2012-09-16 12:33:15 -0700936 if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
937 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
938 }
939 switch (request.getQuality()) {
940 case LocationRequest.ACCURACY_FINE:
941 request.setQuality(LocationRequest.ACCURACY_BLOCK);
942 break;
943 case LocationRequest.POWER_HIGH:
944 request.setQuality(LocationRequest.POWER_LOW);
945 break;
946 }
947 // throttle
948 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
949 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
950 }
951 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
952 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
953 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700954 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700955 // make getFastestInterval() the minimum of interval and fastest interval
956 if (request.getFastestInterval() > request.getInterval()) {
957 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400958 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700959 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400960 }
961
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700962 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700963 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700964 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700965 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700966 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700967 String[] packages = mPackageManager.getPackagesForUid(uid);
968 if (packages == null) {
969 throw new SecurityException("invalid UID " + uid);
970 }
971 for (String pkg : packages) {
972 if (packageName.equals(pkg)) return;
973 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700974 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700975 }
976
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700977 private void checkPendingIntent(PendingIntent intent) {
978 if (intent == null) {
979 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700980 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700981 }
982
983 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
984 int pid, int uid, String packageName) {
985 if (intent == null && listener == null) {
986 throw new IllegalArgumentException("need eiter listener or intent");
987 } else if (intent != null && listener != null) {
988 throw new IllegalArgumentException("cannot register both listener and intent");
989 } else if (intent != null) {
990 checkPendingIntent(intent);
991 return getReceiver(intent, pid, uid, packageName);
992 } else {
993 return getReceiver(listener, pid, uid, packageName);
994 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700995 }
996
Nick Pellye0fd6932012-07-11 10:26:13 -0700997 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700998 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
999 PendingIntent intent, String packageName) {
1000 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1001 checkPackageName(packageName);
1002 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001004 final int pid = Binder.getCallingPid();
1005 final int uid = Binder.getCallingUid();
1006 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001008 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 long identity = Binder.clearCallingIdentity();
1010 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001011 synchronized (mLock) {
1012 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001013 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 } finally {
1015 Binder.restoreCallingIdentity(identity);
1016 }
1017 }
1018
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001019 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1020 int pid, int uid, String packageName) {
1021 // Figure out the provider. Either its explicitly request (legacy use cases), or
1022 // use the fused provider
1023 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1024 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001025 if (name == null) {
1026 throw new IllegalArgumentException("provider name must not be null");
1027 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001028 LocationProviderInterface provider = mProvidersByName.get(name);
1029 if (provider == null) {
1030 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1031 }
1032
1033 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1034 name + " " + request + " from " + packageName + "(" + uid + ")");
1035
1036 UpdateRecord record = new UpdateRecord(name, request, receiver);
1037 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1038 if (oldRecord != null) {
1039 oldRecord.disposeLocked(false);
1040 }
1041
1042 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1043 if (isProviderEnabled) {
1044 applyRequirementsLocked(name);
1045 } else {
1046 // Notify the listener that updates are currently disabled
1047 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 }
1049 }
1050
Nick Pellye0fd6932012-07-11 10:26:13 -07001051 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001052 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1053 String packageName) {
1054 checkPackageName(packageName);
1055 checkPermission();
1056 final int pid = Binder.getCallingPid();
1057 final int uid = Binder.getCallingUid();
1058 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1059
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001060 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001061 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001063 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001064 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001066 } finally {
1067 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 }
1069 }
1070
1071 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001072 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1073
1074 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1075 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1076 synchronized (receiver) {
1077 if (receiver.mPendingBroadcasts > 0) {
1078 decrementPendingBroadcasts();
1079 receiver.mPendingBroadcasts = 0;
1080 }
1081 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 }
1083
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001084 // Record which providers were associated with this listener
1085 HashSet<String> providers = new HashSet<String>();
1086 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1087 if (oldRecords != null) {
1088 // Call dispose() on the obsolete update records.
1089 for (UpdateRecord record : oldRecords.values()) {
1090 record.disposeLocked(false);
1091 }
1092 // Accumulate providers
1093 providers.addAll(oldRecords.keySet());
1094 }
1095
1096 // update provider
1097 for (String provider : providers) {
1098 // If provider is already disabled, don't need to do anything
1099 if (!isAllowedBySettingsLocked(provider)) {
1100 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 }
1102
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001103 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 }
1105 }
1106
Nick Pellye0fd6932012-07-11 10:26:13 -07001107 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001108 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001109 if (D) Log.d(TAG, "getLastLocation: " + request);
1110 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1111 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001112 checkPackageName(packageName);
1113
1114 if (mBlacklist.isBlacklisted(packageName)) {
1115 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1116 packageName);
1117 return null;
1118 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001119
1120 synchronized (mLock) {
1121 // Figure out the provider. Either its explicitly request (deprecated API's),
1122 // or use the fused provider
1123 String name = request.getProvider();
1124 if (name == null) name = LocationManager.FUSED_PROVIDER;
1125 LocationProviderInterface provider = mProvidersByName.get(name);
1126 if (provider == null) return null;
1127
1128 if (!isAllowedBySettingsLocked(name)) return null;
1129
1130 Location location = mLastLocation.get(name);
Victoria Lease09016ab2012-09-16 12:33:15 -07001131 if (location == null) {
1132 return null;
1133 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001134 if (ACCESS_FINE_LOCATION.equals(perm)) {
1135 return location;
1136 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001137 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1138 if (noGPSLocation != null) {
1139 return mLocationFudger.getOrCreate(noGPSLocation);
1140 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001141 }
1142 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001143 return null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001144 }
1145
1146 @Override
1147 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1148 String packageName) {
1149 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001150 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001151 checkPermissionAndRequest(request);
1152 checkPendingIntent(intent);
1153 checkPackageName(packageName);
1154
1155 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1156
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001157 // geo-fence manager uses the public location API, need to clear identity
1158 int uid = Binder.getCallingUid();
1159 long identity = Binder.clearCallingIdentity();
1160 try {
1161 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1162 } finally {
1163 Binder.restoreCallingIdentity(identity);
1164 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001165 }
1166
1167 @Override
1168 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001169 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001170 checkPendingIntent(intent);
1171 checkPackageName(packageName);
1172
1173 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1174
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001175 // geo-fence manager uses the public location API, need to clear identity
1176 long identity = Binder.clearCallingIdentity();
1177 try {
1178 mGeofenceManager.removeFence(geofence, intent);
1179 } finally {
1180 Binder.restoreCallingIdentity(identity);
1181 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001182 }
1183
1184
1185 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001187 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 return false;
1189 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001190 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 PackageManager.PERMISSION_GRANTED) {
1192 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1193 }
1194
1195 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001196 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001198 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 return false;
1200 }
1201 return true;
1202 }
1203
Nick Pellye0fd6932012-07-11 10:26:13 -07001204 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001205 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001206 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001207 try {
1208 mGpsStatusProvider.removeGpsStatusListener(listener);
1209 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001210 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001211 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 }
1213 }
1214
Nick Pellye0fd6932012-07-11 10:26:13 -07001215 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001217 if (provider == null) {
1218 // throw NullPointerException to remain compatible with previous implementation
1219 throw new NullPointerException();
1220 }
1221
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001224 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 != PackageManager.PERMISSION_GRANTED)) {
1226 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1227 }
1228
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001229 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001230 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001231 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001232
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001233 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 }
1235 }
1236
Nick Pellye0fd6932012-07-11 10:26:13 -07001237 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001238 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001239 if (Binder.getCallingUid() != Process.myUid()) {
1240 throw new SecurityException(
1241 "calling sendNiResponse from outside of the system is not allowed");
1242 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001243 try {
1244 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001245 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001246 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001247 return false;
1248 }
1249 }
1250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001252 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001253 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 * accessed by the caller
1255 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001256 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001257 public ProviderProperties getProviderProperties(String provider) {
1258 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001260 LocationProviderInterface p;
1261 synchronized (mLock) {
1262 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 }
1264
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001265 if (p == null) return null;
1266 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 }
1268
Nick Pellye0fd6932012-07-11 10:26:13 -07001269 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001271 checkPermission();
1272 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1273
1274 synchronized (mLock) {
1275 LocationProviderInterface p = mProvidersByName.get(provider);
1276 if (p == null) return false;
1277
1278 return isAllowedBySettingsLocked(provider);
1279 }
1280 }
1281
1282 private void checkCallerIsProvider() {
1283 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1284 == PackageManager.PERMISSION_GRANTED) {
1285 return;
1286 }
1287
1288 // Previously we only used the INSTALL_LOCATION_PROVIDER
1289 // check. But that is system or signature
1290 // protection level which is not flexible enough for
1291 // providers installed oustide the system image. So
1292 // also allow providers with a UID matching the
1293 // currently bound package name
1294
1295 int uid = Binder.getCallingUid();
1296
1297 if (mGeocodeProvider != null) {
1298 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1299 }
1300 for (LocationProviderProxy proxy : mProxyProviders) {
1301 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1302 }
1303 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1304 "or UID of a currently bound location provider");
1305 }
1306
1307 private boolean doesPackageHaveUid(int uid, String packageName) {
1308 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 return false;
1310 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001311 try {
1312 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1313 if (appInfo.uid != uid) {
1314 return false;
1315 }
1316 } catch (NameNotFoundException e) {
1317 return false;
1318 }
1319 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 }
1321
Nick Pellye0fd6932012-07-11 10:26:13 -07001322 @Override
Mike Lockwooda4903f252010-02-17 06:42:23 -05001323 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001325
Nick Pelly2eeeec22012-07-18 13:13:37 -07001326 if (!location.isComplete()) {
1327 Log.w(TAG, "Dropping incomplete location: " + location);
1328 return;
1329 }
1330
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001331 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1332 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f252010-02-17 06:42:23 -05001333 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001334 mLocationHandler.sendMessageAtFrontOfQueue(m);
1335 }
1336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337
1338 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1339 // Always broadcast the first update
1340 if (lastLoc == null) {
1341 return true;
1342 }
1343
Nick Pellyf1be6862012-05-15 10:53:42 -07001344 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001345 long minTime = record.mRequest.getFastestInterval();
Nick Pelly2eeeec22012-07-18 13:13:37 -07001346 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001347 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 return false;
1349 }
1350
1351 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001352 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 if (minDistance > 0.0) {
1354 if (loc.distanceTo(lastLoc) <= minDistance) {
1355 return false;
1356 }
1357 }
1358
1359 return true;
1360 }
1361
Mike Lockwooda4903f252010-02-17 06:42:23 -05001362 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001363 if (D) Log.d(TAG, "incoming location: " + location);
1364
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001365 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f252010-02-17 06:42:23 -05001366 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001368 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001370 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001371 if (p == null) return;
1372
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001373 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001374 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1375 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001376 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001377 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001378 lastLocation = new Location(provider);
1379 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001380 } else {
1381 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1382 if (noGPSLocation == null && lastNoGPSLocation != null) {
1383 // New location has no no-GPS location: adopt last no-GPS location. This is set
1384 // directly into location because we do not want to notify COARSE clients.
1385 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1386 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001387 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001388 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389
Victoria Lease09016ab2012-09-16 12:33:15 -07001390 // Fetch coarse location
1391 Location coarseLocation = null;
1392 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1393 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1394 }
1395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 // Fetch latest status update time
1397 long newStatusUpdateTime = p.getStatusUpdateTime();
1398
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001399 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 Bundle extras = new Bundle();
1401 int status = p.getStatus(extras);
1402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001404 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001407 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001409 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001410
1411 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1412 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1413 receiver.mPackageName);
1414 continue;
1415 }
1416
Victoria Lease09016ab2012-09-16 12:33:15 -07001417 Location notifyLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001418 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001419 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001420 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001421 notifyLocation = coarseLocation; // use coarse location if available
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001422 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001423 if (notifyLocation != null) {
1424 Location lastLoc = r.mLastFixBroadcast;
1425 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1426 if (lastLoc == null) {
1427 lastLoc = new Location(notifyLocation);
1428 r.mLastFixBroadcast = lastLoc;
1429 } else {
1430 lastLoc.set(notifyLocation);
1431 }
1432 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1433 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1434 receiverDead = true;
1435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 }
1437 }
1438
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001439 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001441 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001443 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001445 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001446 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001447 }
1448 }
1449
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001450 // track expired records
1451 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1452 if (deadUpdateRecords == null) {
1453 deadUpdateRecords = new ArrayList<UpdateRecord>();
1454 }
1455 deadUpdateRecords.add(r);
1456 }
1457 // track dead receivers
1458 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001459 if (deadReceivers == null) {
1460 deadReceivers = new ArrayList<Receiver>();
1461 }
1462 if (!deadReceivers.contains(receiver)) {
1463 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 }
1465 }
1466 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001467
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001468 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001470 for (Receiver receiver : deadReceivers) {
1471 removeUpdatesLocked(receiver);
1472 }
1473 }
1474 if (deadUpdateRecords != null) {
1475 for (UpdateRecord r : deadUpdateRecords) {
1476 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 }
1478 }
1479 }
1480
1481 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 @Override
1483 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001484 switch (msg.what) {
1485 case MSG_LOCATION_CHANGED:
1486 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1487 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 }
1489 }
1490 }
1491
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001492 private void handleLocationChanged(Location location, boolean passive) {
1493 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001494
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001495 if (!passive) {
1496 // notify passive provider of the new location
1497 mPassiveProvider.updateLocation(location);
1498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001500 synchronized (mLock) {
1501 if (isAllowedBySettingsLocked(provider)) {
1502 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506
Mike Lockwoode97ae402010-09-29 15:23:46 -04001507 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1508 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001509 public void onPackageDisappeared(String packageName, int reason) {
1510 // remove all receivers associated with this package name
1511 synchronized (mLock) {
1512 ArrayList<Receiver> deadReceivers = null;
1513
1514 for (Receiver receiver : mReceivers.values()) {
1515 if (receiver.mPackageName.equals(packageName)) {
1516 if (deadReceivers == null) {
1517 deadReceivers = new ArrayList<Receiver>();
1518 }
1519 deadReceivers.add(receiver);
1520 }
1521 }
1522
1523 // perform removal outside of mReceivers loop
1524 if (deadReceivers != null) {
1525 for (Receiver receiver : deadReceivers) {
1526 removeUpdatesLocked(receiver);
1527 }
1528 }
1529 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001530 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001531 };
1532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 // Wake locks
1534
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001535 private void incrementPendingBroadcasts() {
1536 synchronized (mWakeLock) {
1537 if (mPendingBroadcasts++ == 0) {
1538 try {
1539 mWakeLock.acquire();
1540 log("Acquired wakelock");
1541 } catch (Exception e) {
1542 // This is to catch a runtime exception thrown when we try to release an
1543 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001544 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001545 }
1546 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001547 }
1548 }
1549
1550 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001551 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001552 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001553 try {
1554 // Release wake lock
1555 if (mWakeLock.isHeld()) {
1556 mWakeLock.release();
1557 log("Released wakelock");
1558 } else {
1559 log("Can't release wakelock again!");
1560 }
1561 } catch (Exception e) {
1562 // This is to catch a runtime exception thrown when we try to release an
1563 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001564 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001565 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001566 }
1567 }
1568 }
1569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 // Geocoder
1571
Nick Pellye0fd6932012-07-11 10:26:13 -07001572 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001573 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001574 return mGeocodeProvider != null;
1575 }
1576
Nick Pellye0fd6932012-07-11 10:26:13 -07001577 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001579 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001580 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001581 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1582 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001584 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 }
1586
Mike Lockwooda55c3212009-04-15 11:10:11 -04001587
Nick Pellye0fd6932012-07-11 10:26:13 -07001588 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001589 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001590 double lowerLeftLatitude, double lowerLeftLongitude,
1591 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001592 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001593
1594 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001595 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1596 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1597 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001599 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 }
1601
1602 // Mock Providers
1603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 private void checkMockPermissionsSafe() {
1605 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1606 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1607 if (!allowMocks) {
1608 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1609 }
1610
1611 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1612 PackageManager.PERMISSION_GRANTED) {
1613 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 }
1616
Nick Pellye0fd6932012-07-11 10:26:13 -07001617 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001618 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 checkMockPermissionsSafe();
1620
Mike Lockwooda4903f252010-02-17 06:42:23 -05001621 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1622 throw new IllegalArgumentException("Cannot mock the passive location provider");
1623 }
1624
Mike Lockwood86328a92009-10-23 08:38:25 -04001625 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001626 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001627 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001628 // remove the real provider if we are replacing GPS or network provider
1629 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001630 || LocationManager.NETWORK_PROVIDER.equals(name)
1631 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001632 LocationProviderInterface p = mProvidersByName.get(name);
1633 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001634 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001635 }
1636 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001637 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001638 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1639 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001640 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001641 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001642 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 updateProvidersLocked();
1644 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001645 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 }
1647
Nick Pellye0fd6932012-07-11 10:26:13 -07001648 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001649 public void removeTestProvider(String provider) {
1650 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001651 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001652 MockProvider mockProvider = mMockProviders.get(provider);
1653 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1655 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001656 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001657 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001658 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001659
1660 // reinstate real provider if available
1661 LocationProviderInterface realProvider = mRealProviders.get(provider);
1662 if (realProvider != null) {
1663 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001664 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001665 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001667 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 }
1669 }
1670
Nick Pellye0fd6932012-07-11 10:26:13 -07001671 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 public void setTestProviderLocation(String provider, Location loc) {
1673 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001674 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001675 MockProvider mockProvider = mMockProviders.get(provider);
1676 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1678 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001679 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1680 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001681 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001682 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 }
1684 }
1685
Nick Pellye0fd6932012-07-11 10:26:13 -07001686 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 public void clearTestProviderLocation(String provider) {
1688 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001689 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001690 MockProvider mockProvider = mMockProviders.get(provider);
1691 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1693 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001694 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 }
1696 }
1697
Nick Pellye0fd6932012-07-11 10:26:13 -07001698 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 public void setTestProviderEnabled(String provider, boolean enabled) {
1700 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001701 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001702 MockProvider mockProvider = mMockProviders.get(provider);
1703 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1705 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001706 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001708 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 mEnabledProviders.add(provider);
1710 mDisabledProviders.remove(provider);
1711 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001712 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 mEnabledProviders.remove(provider);
1714 mDisabledProviders.add(provider);
1715 }
1716 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001717 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 }
1719 }
1720
Nick Pellye0fd6932012-07-11 10:26:13 -07001721 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 public void clearTestProviderEnabled(String provider) {
1723 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001724 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001725 MockProvider mockProvider = mMockProviders.get(provider);
1726 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1728 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001729 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 mEnabledProviders.remove(provider);
1731 mDisabledProviders.remove(provider);
1732 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001733 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 }
1735 }
1736
Nick Pellye0fd6932012-07-11 10:26:13 -07001737 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1739 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001740 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001741 MockProvider mockProvider = mMockProviders.get(provider);
1742 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1744 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001745 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 }
1747 }
1748
Nick Pellye0fd6932012-07-11 10:26:13 -07001749 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 public void clearTestProviderStatus(String provider) {
1751 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001752 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001753 MockProvider mockProvider = mMockProviders.get(provider);
1754 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1756 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001757 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 }
1759 }
1760
1761 private void log(String log) {
1762 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001763 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 }
1765 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001766
1767 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1769 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1770 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001771 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 + Binder.getCallingPid()
1773 + ", uid=" + Binder.getCallingUid());
1774 return;
1775 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001776
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001777 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001780 for (Receiver receiver : mReceivers.values()) {
1781 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001784 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1785 pw.println(" " + entry.getKey() + ":");
1786 for (UpdateRecord record : entry.getValue()) {
1787 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001788 }
1789 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001791 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1792 String provider = entry.getKey();
1793 Location location = entry.getValue();
1794 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001796
Nick Pellye0fd6932012-07-11 10:26:13 -07001797 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001798
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 if (mEnabledProviders.size() > 0) {
1800 pw.println(" Enabled Providers:");
1801 for (String i : mEnabledProviders) {
1802 pw.println(" " + i);
1803 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 }
1806 if (mDisabledProviders.size() > 0) {
1807 pw.println(" Disabled Providers:");
1808 for (String i : mDisabledProviders) {
1809 pw.println(" " + i);
1810 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001812 pw.append(" ");
1813 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 if (mMockProviders.size() > 0) {
1815 pw.println(" Mock Providers:");
1816 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001817 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 }
1819 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001820
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001821 pw.append(" fudger: ");
1822 mLocationFudger.dump(fd, pw, args);
1823
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001824 if (args.length > 0 && "short".equals(args[0])) {
1825 return;
1826 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001827 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001828 pw.print(provider.getName() + " Internal State");
1829 if (provider instanceof LocationProviderProxy) {
1830 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1831 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001832 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001833 pw.println(":");
1834 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001835 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 }
1837 }
1838}