blob: 974fdbbf935571f8ddcbb5c292d7d077e74ba791 [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
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700919 private String checkPermissionAndRequest(LocationRequest request) {
920 String perm = checkPermission();
921
922 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700923 switch (request.getQuality()) {
924 case LocationRequest.ACCURACY_FINE:
925 request.setQuality(LocationRequest.ACCURACY_BLOCK);
926 break;
927 case LocationRequest.POWER_HIGH:
928 request.setQuality(LocationRequest.POWER_LOW);
929 break;
930 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700931 // throttle
932 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
933 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
934 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700935 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
936 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
937 }
938 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700939 // make getFastestInterval() the minimum of interval and fastest interval
940 if (request.getFastestInterval() > request.getInterval()) {
941 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400942 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700943 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400944 }
945
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700946 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700947 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700948 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700949 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700950 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700951 String[] packages = mPackageManager.getPackagesForUid(uid);
952 if (packages == null) {
953 throw new SecurityException("invalid UID " + uid);
954 }
955 for (String pkg : packages) {
956 if (packageName.equals(pkg)) return;
957 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700958 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700959 }
960
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700961 private void checkPendingIntent(PendingIntent intent) {
962 if (intent == null) {
963 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700964 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700965 }
966
967 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
968 int pid, int uid, String packageName) {
969 if (intent == null && listener == null) {
970 throw new IllegalArgumentException("need eiter listener or intent");
971 } else if (intent != null && listener != null) {
972 throw new IllegalArgumentException("cannot register both listener and intent");
973 } else if (intent != null) {
974 checkPendingIntent(intent);
975 return getReceiver(intent, pid, uid, packageName);
976 } else {
977 return getReceiver(listener, pid, uid, packageName);
978 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700979 }
980
Nick Pellye0fd6932012-07-11 10:26:13 -0700981 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700982 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
983 PendingIntent intent, String packageName) {
984 if (request == null) request = DEFAULT_LOCATION_REQUEST;
985 checkPackageName(packageName);
986 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700988 final int pid = Binder.getCallingPid();
989 final int uid = Binder.getCallingUid();
990 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991
Nick Pelly2b7a0d02012-08-17 15:09:44 -0700992 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 long identity = Binder.clearCallingIdentity();
994 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700995 synchronized (mLock) {
996 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400997 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 } finally {
999 Binder.restoreCallingIdentity(identity);
1000 }
1001 }
1002
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001003 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1004 int pid, int uid, String packageName) {
1005 // Figure out the provider. Either its explicitly request (legacy use cases), or
1006 // use the fused provider
1007 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1008 String name = request.getProvider();
1009 if (name == null) name = LocationManager.FUSED_PROVIDER;
1010 LocationProviderInterface provider = mProvidersByName.get(name);
1011 if (provider == null) {
1012 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1013 }
1014
1015 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1016 name + " " + request + " from " + packageName + "(" + uid + ")");
1017
1018 UpdateRecord record = new UpdateRecord(name, request, receiver);
1019 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1020 if (oldRecord != null) {
1021 oldRecord.disposeLocked(false);
1022 }
1023
1024 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1025 if (isProviderEnabled) {
1026 applyRequirementsLocked(name);
1027 } else {
1028 // Notify the listener that updates are currently disabled
1029 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 }
1031 }
1032
Nick Pellye0fd6932012-07-11 10:26:13 -07001033 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001034 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1035 String packageName) {
1036 checkPackageName(packageName);
1037 checkPermission();
1038 final int pid = Binder.getCallingPid();
1039 final int uid = Binder.getCallingUid();
1040 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1041
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001042 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001043 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001045 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001046 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001048 } finally {
1049 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 }
1051 }
1052
1053 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001054 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1055
1056 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1057 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1058 synchronized (receiver) {
1059 if (receiver.mPendingBroadcasts > 0) {
1060 decrementPendingBroadcasts();
1061 receiver.mPendingBroadcasts = 0;
1062 }
1063 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 }
1065
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001066 // Record which providers were associated with this listener
1067 HashSet<String> providers = new HashSet<String>();
1068 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1069 if (oldRecords != null) {
1070 // Call dispose() on the obsolete update records.
1071 for (UpdateRecord record : oldRecords.values()) {
1072 record.disposeLocked(false);
1073 }
1074 // Accumulate providers
1075 providers.addAll(oldRecords.keySet());
1076 }
1077
1078 // update provider
1079 for (String provider : providers) {
1080 // If provider is already disabled, don't need to do anything
1081 if (!isAllowedBySettingsLocked(provider)) {
1082 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 }
1084
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001085 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 }
1087 }
1088
Nick Pellye0fd6932012-07-11 10:26:13 -07001089 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001090 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001091 if (D) Log.d(TAG, "getLastLocation: " + request);
1092 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1093 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001094 checkPackageName(packageName);
1095
1096 if (mBlacklist.isBlacklisted(packageName)) {
1097 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1098 packageName);
1099 return null;
1100 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001101
1102 synchronized (mLock) {
1103 // Figure out the provider. Either its explicitly request (deprecated API's),
1104 // or use the fused provider
1105 String name = request.getProvider();
1106 if (name == null) name = LocationManager.FUSED_PROVIDER;
1107 LocationProviderInterface provider = mProvidersByName.get(name);
1108 if (provider == null) return null;
1109
1110 if (!isAllowedBySettingsLocked(name)) return null;
1111
1112 Location location = mLastLocation.get(name);
1113 if (ACCESS_FINE_LOCATION.equals(perm)) {
1114 return location;
1115 } else {
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001116 return mLocationFudger.getOrCreate(location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001117 }
1118 }
1119 }
1120
1121 @Override
1122 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1123 String packageName) {
1124 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001125 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001126 checkPermissionAndRequest(request);
1127 checkPendingIntent(intent);
1128 checkPackageName(packageName);
1129
1130 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1131
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001132 // geo-fence manager uses the public location API, need to clear identity
1133 int uid = Binder.getCallingUid();
1134 long identity = Binder.clearCallingIdentity();
1135 try {
1136 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1137 } finally {
1138 Binder.restoreCallingIdentity(identity);
1139 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001140 }
1141
1142 @Override
1143 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001144 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001145 checkPendingIntent(intent);
1146 checkPackageName(packageName);
1147
1148 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1149
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001150 // geo-fence manager uses the public location API, need to clear identity
1151 long identity = Binder.clearCallingIdentity();
1152 try {
1153 mGeofenceManager.removeFence(geofence, intent);
1154 } finally {
1155 Binder.restoreCallingIdentity(identity);
1156 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001157 }
1158
1159
1160 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001162 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 return false;
1164 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001165 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 PackageManager.PERMISSION_GRANTED) {
1167 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1168 }
1169
1170 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001171 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001173 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 return false;
1175 }
1176 return true;
1177 }
1178
Nick Pellye0fd6932012-07-11 10:26:13 -07001179 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001181 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001182 try {
1183 mGpsStatusProvider.removeGpsStatusListener(listener);
1184 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001185 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 }
1188 }
1189
Nick Pellye0fd6932012-07-11 10:26:13 -07001190 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001192 if (provider == null) {
1193 // throw NullPointerException to remain compatible with previous implementation
1194 throw new NullPointerException();
1195 }
1196
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001197 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001199 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 != PackageManager.PERMISSION_GRANTED)) {
1201 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1202 }
1203
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001204 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001205 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001206 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001207
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001208 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001209 }
1210 }
1211
Nick Pellye0fd6932012-07-11 10:26:13 -07001212 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001213 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001214 if (Binder.getCallingUid() != Process.myUid()) {
1215 throw new SecurityException(
1216 "calling sendNiResponse from outside of the system is not allowed");
1217 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001218 try {
1219 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001220 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001221 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001222 return false;
1223 }
1224 }
1225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001227 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001228 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 * accessed by the caller
1230 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001231 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001232 public ProviderProperties getProviderProperties(String provider) {
1233 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001235 LocationProviderInterface p;
1236 synchronized (mLock) {
1237 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 }
1239
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001240 if (p == null) return null;
1241 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 }
1243
Nick Pellye0fd6932012-07-11 10:26:13 -07001244 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001245 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001246 checkPermission();
1247 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1248
1249 synchronized (mLock) {
1250 LocationProviderInterface p = mProvidersByName.get(provider);
1251 if (p == null) return false;
1252
1253 return isAllowedBySettingsLocked(provider);
1254 }
1255 }
1256
1257 private void checkCallerIsProvider() {
1258 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1259 == PackageManager.PERMISSION_GRANTED) {
1260 return;
1261 }
1262
1263 // Previously we only used the INSTALL_LOCATION_PROVIDER
1264 // check. But that is system or signature
1265 // protection level which is not flexible enough for
1266 // providers installed oustide the system image. So
1267 // also allow providers with a UID matching the
1268 // currently bound package name
1269
1270 int uid = Binder.getCallingUid();
1271
1272 if (mGeocodeProvider != null) {
1273 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1274 }
1275 for (LocationProviderProxy proxy : mProxyProviders) {
1276 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1277 }
1278 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1279 "or UID of a currently bound location provider");
1280 }
1281
1282 private boolean doesPackageHaveUid(int uid, String packageName) {
1283 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 return false;
1285 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001286 try {
1287 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1288 if (appInfo.uid != uid) {
1289 return false;
1290 }
1291 } catch (NameNotFoundException e) {
1292 return false;
1293 }
1294 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 }
1296
Nick Pellye0fd6932012-07-11 10:26:13 -07001297 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001298 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001299 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001300
Nick Pelly2eeeec22012-07-18 13:13:37 -07001301 if (!location.isComplete()) {
1302 Log.w(TAG, "Dropping incomplete location: " + location);
1303 return;
1304 }
1305
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001306 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1307 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001308 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001309 mLocationHandler.sendMessageAtFrontOfQueue(m);
1310 }
1311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312
1313 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1314 // Always broadcast the first update
1315 if (lastLoc == null) {
1316 return true;
1317 }
1318
Nick Pellyf1be6862012-05-15 10:53:42 -07001319 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001320 long minTime = record.mRequest.getFastestInterval();
Nick Pelly2eeeec22012-07-18 13:13:37 -07001321 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001322 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 return false;
1324 }
1325
1326 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001327 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 if (minDistance > 0.0) {
1329 if (loc.distanceTo(lastLoc) <= minDistance) {
1330 return false;
1331 }
1332 }
1333
1334 return true;
1335 }
1336
Mike Lockwooda4903f22010-02-17 06:42:23 -05001337 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001338 if (D) Log.d(TAG, "incoming location: " + location);
1339
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001340 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001341 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001343 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001345 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001346 if (p == null) return;
1347
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001348 // Add the coarse location as an extra
1349 Location coarse = mLocationFudger.getOrCreate(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001351 // Update last known locations
1352 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001353 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001354 lastLocation = new Location(provider);
1355 mLastLocation.put(provider, lastLocation);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001356 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001357 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 // Fetch latest status update time
1360 long newStatusUpdateTime = p.getStatusUpdateTime();
1361
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001362 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363 Bundle extras = new Bundle();
1364 int status = p.getStatus(extras);
1365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001367 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001370 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001372 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001373
1374 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1375 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1376 receiver.mPackageName);
1377 continue;
1378 }
1379
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001380 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1381 location = lastLocation; // use fine location
1382 } else {
1383 location = coarse; // use coarse location
1384 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001386 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001387 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1388 if (lastLoc == null) {
1389 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001390 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001391 } else {
1392 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001394 if (!receiver.callLocationChangedLocked(location)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001395 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001396 receiverDead = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 }
1398 }
1399
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001400 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1402 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1403
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001404 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001406 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001407 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001408 }
1409 }
1410
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001411 // track expired records
1412 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1413 if (deadUpdateRecords == null) {
1414 deadUpdateRecords = new ArrayList<UpdateRecord>();
1415 }
1416 deadUpdateRecords.add(r);
1417 }
1418 // track dead receivers
1419 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001420 if (deadReceivers == null) {
1421 deadReceivers = new ArrayList<Receiver>();
1422 }
1423 if (!deadReceivers.contains(receiver)) {
1424 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 }
1426 }
1427 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001428
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001429 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001431 for (Receiver receiver : deadReceivers) {
1432 removeUpdatesLocked(receiver);
1433 }
1434 }
1435 if (deadUpdateRecords != null) {
1436 for (UpdateRecord r : deadUpdateRecords) {
1437 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 }
1439 }
1440 }
1441
1442 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 @Override
1444 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001445 switch (msg.what) {
1446 case MSG_LOCATION_CHANGED:
1447 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1448 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 }
1450 }
1451 }
1452
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001453 private void handleLocationChanged(Location location, boolean passive) {
1454 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001455
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001456 if (!passive) {
1457 // notify passive provider of the new location
1458 mPassiveProvider.updateLocation(location);
1459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001461 synchronized (mLock) {
1462 if (isAllowedBySettingsLocked(provider)) {
1463 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001466 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467
Mike Lockwoode97ae402010-09-29 15:23:46 -04001468 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1469 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001470 public void onPackageDisappeared(String packageName, int reason) {
1471 // remove all receivers associated with this package name
1472 synchronized (mLock) {
1473 ArrayList<Receiver> deadReceivers = null;
1474
1475 for (Receiver receiver : mReceivers.values()) {
1476 if (receiver.mPackageName.equals(packageName)) {
1477 if (deadReceivers == null) {
1478 deadReceivers = new ArrayList<Receiver>();
1479 }
1480 deadReceivers.add(receiver);
1481 }
1482 }
1483
1484 // perform removal outside of mReceivers loop
1485 if (deadReceivers != null) {
1486 for (Receiver receiver : deadReceivers) {
1487 removeUpdatesLocked(receiver);
1488 }
1489 }
1490 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001491 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001492 };
1493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 // Wake locks
1495
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001496 private void incrementPendingBroadcasts() {
1497 synchronized (mWakeLock) {
1498 if (mPendingBroadcasts++ == 0) {
1499 try {
1500 mWakeLock.acquire();
1501 log("Acquired wakelock");
1502 } catch (Exception e) {
1503 // This is to catch a runtime exception thrown when we try to release an
1504 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001505 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001506 }
1507 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001508 }
1509 }
1510
1511 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001512 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001513 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001514 try {
1515 // Release wake lock
1516 if (mWakeLock.isHeld()) {
1517 mWakeLock.release();
1518 log("Released wakelock");
1519 } else {
1520 log("Can't release wakelock again!");
1521 }
1522 } catch (Exception e) {
1523 // This is to catch a runtime exception thrown when we try to release an
1524 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001525 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001526 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001527 }
1528 }
1529 }
1530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531 // Geocoder
1532
Nick Pellye0fd6932012-07-11 10:26:13 -07001533 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001534 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001535 return mGeocodeProvider != null;
1536 }
1537
Nick Pellye0fd6932012-07-11 10:26:13 -07001538 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001540 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001541 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001542 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1543 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001545 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 }
1547
Mike Lockwooda55c3212009-04-15 11:10:11 -04001548
Nick Pellye0fd6932012-07-11 10:26:13 -07001549 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001551 double lowerLeftLatitude, double lowerLeftLongitude,
1552 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001553 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001554
1555 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001556 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1557 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1558 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001560 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 }
1562
1563 // Mock Providers
1564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 private void checkMockPermissionsSafe() {
1566 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1567 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1568 if (!allowMocks) {
1569 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1570 }
1571
1572 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1573 PackageManager.PERMISSION_GRANTED) {
1574 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 }
1577
Nick Pellye0fd6932012-07-11 10:26:13 -07001578 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001579 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 checkMockPermissionsSafe();
1581
Mike Lockwooda4903f22010-02-17 06:42:23 -05001582 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1583 throw new IllegalArgumentException("Cannot mock the passive location provider");
1584 }
1585
Mike Lockwood86328a92009-10-23 08:38:25 -04001586 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001587 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001588 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001589 // remove the real provider if we are replacing GPS or network provider
1590 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001591 || LocationManager.NETWORK_PROVIDER.equals(name)
1592 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001593 LocationProviderInterface p = mProvidersByName.get(name);
1594 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001595 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001596 }
1597 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001598 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1600 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001601 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001602 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001603 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 updateProvidersLocked();
1605 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001606 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
1608
Nick Pellye0fd6932012-07-11 10:26:13 -07001609 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 public void removeTestProvider(String provider) {
1611 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001612 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001613 MockProvider mockProvider = mMockProviders.get(provider);
1614 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1616 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001617 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001618 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001619 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001620
1621 // reinstate real provider if available
1622 LocationProviderInterface realProvider = mRealProviders.get(provider);
1623 if (realProvider != null) {
1624 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001625 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001626 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001628 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 }
1630 }
1631
Nick Pellye0fd6932012-07-11 10:26:13 -07001632 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 public void setTestProviderLocation(String provider, Location loc) {
1634 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001635 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001636 MockProvider mockProvider = mMockProviders.get(provider);
1637 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001638 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1639 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001640 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1641 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001642 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001643 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 }
1645 }
1646
Nick Pellye0fd6932012-07-11 10:26:13 -07001647 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 public void clearTestProviderLocation(String provider) {
1649 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001650 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001651 MockProvider mockProvider = mMockProviders.get(provider);
1652 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1654 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001655 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 }
1657 }
1658
Nick Pellye0fd6932012-07-11 10:26:13 -07001659 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 public void setTestProviderEnabled(String provider, boolean enabled) {
1661 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001662 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001663 MockProvider mockProvider = mMockProviders.get(provider);
1664 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1666 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001667 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001669 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 mEnabledProviders.add(provider);
1671 mDisabledProviders.remove(provider);
1672 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001673 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 mEnabledProviders.remove(provider);
1675 mDisabledProviders.add(provider);
1676 }
1677 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001678 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 }
1680 }
1681
Nick Pellye0fd6932012-07-11 10:26:13 -07001682 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 public void clearTestProviderEnabled(String provider) {
1684 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001685 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001686 MockProvider mockProvider = mMockProviders.get(provider);
1687 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1689 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001690 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 mEnabledProviders.remove(provider);
1692 mDisabledProviders.remove(provider);
1693 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001694 Binder.restoreCallingIdentity(identity);
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 setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
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 Lockwood7ec434e2009-03-27 07:46:48 -07001706 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 }
1708 }
1709
Nick Pellye0fd6932012-07-11 10:26:13 -07001710 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 public void clearTestProviderStatus(String provider) {
1712 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001713 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001714 MockProvider mockProvider = mMockProviders.get(provider);
1715 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1717 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001718 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 }
1720 }
1721
1722 private void log(String log) {
1723 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001724 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 }
1726 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001727
1728 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1730 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1731 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001732 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 + Binder.getCallingPid()
1734 + ", uid=" + Binder.getCallingUid());
1735 return;
1736 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001737
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001738 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001741 for (Receiver receiver : mReceivers.values()) {
1742 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001745 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1746 pw.println(" " + entry.getKey() + ":");
1747 for (UpdateRecord record : entry.getValue()) {
1748 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001749 }
1750 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001752 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1753 String provider = entry.getKey();
1754 Location location = entry.getValue();
1755 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001757
Nick Pellye0fd6932012-07-11 10:26:13 -07001758 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 if (mEnabledProviders.size() > 0) {
1761 pw.println(" Enabled Providers:");
1762 for (String i : mEnabledProviders) {
1763 pw.println(" " + i);
1764 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 }
1767 if (mDisabledProviders.size() > 0) {
1768 pw.println(" Disabled Providers:");
1769 for (String i : mDisabledProviders) {
1770 pw.println(" " + i);
1771 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001773 pw.append(" ");
1774 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 if (mMockProviders.size() > 0) {
1776 pw.println(" Mock Providers:");
1777 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001778 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 }
1780 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001781
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001782 pw.append(" fudger: ");
1783 mLocationFudger.dump(fd, pw, args);
1784
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001785 if (args.length > 0 && "short".equals(args[0])) {
1786 return;
1787 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001788 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001789 pw.print(provider.getName() + " Internal State");
1790 if (provider instanceof LocationProviderProxy) {
1791 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1792 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001793 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001794 pw.println(":");
1795 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001796 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 }
1798 }
1799}