blob: 840d432ae52ebd13af8f7724a22f26db932d9334 [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
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700604 /**
605 * Returns all providers by name, including passive, but excluding
606 * fused.
607 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700608 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700610 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700612 ArrayList<String> out;
613 synchronized (mLock) {
614 out = new ArrayList<String>(mProviders.size());
615 for (LocationProviderInterface provider : mProviders) {
616 String name = provider.getName();
617 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700618 continue;
619 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 out.add(name);
621 }
622 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700623
624 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 return out;
626 }
627
Mike Lockwood03ca2162010-04-01 08:10:09 -0700628 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700629 * Return all providers by name, that match criteria and are optionally
630 * enabled.
631 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700632 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700633 @Override
634 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
635 checkPermission();
Mike Lockwood03ca2162010-04-01 08:10:09 -0700636
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700637 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700638 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700639 out = new ArrayList<String>(mProviders.size());
640 for (LocationProviderInterface provider : mProviders) {
641 String name = provider.getName();
642 if (LocationManager.FUSED_PROVIDER.equals(name)) {
643 continue;
644 }
645 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
646 continue;
647 }
648 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
649 name, provider.getProperties(), criteria)) {
650 continue;
651 }
652 out.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700653 }
654 }
655
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700656 if (D) Log.d(TAG, "getProviders()=" + out);
657 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700658 }
659
660 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 * Return the name of the best provider given a Criteria object.
662 * This method has been deprecated from the public API,
663 * and the whole LoactionProvider (including #meetsCriteria)
664 * has been deprecated as well. So this method now uses
665 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700666 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700667 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700668 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700669 String result = null;
670 checkPermission();
671
672 List<String> providers = getProviders(criteria, enabledOnly);
673 if (providers.size() < 1) {
674 result = pickBest(providers);
675 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
676 return result;
677 }
678 providers = getProviders(null, enabledOnly);
679 if (providers.size() >= 1) {
680 result = pickBest(providers);
681 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
682 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700683 }
684
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700685 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700686 return null;
687 }
688
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700689 private String pickBest(List<String> providers) {
690 if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
691 return LocationManager.NETWORK_PROVIDER;
692 } else if (providers.contains(LocationManager.GPS_PROVIDER)) {
693 return LocationManager.GPS_PROVIDER;
694 } else {
695 return providers.get(0);
696 }
697 }
698
Nick Pellye0fd6932012-07-11 10:26:13 -0700699 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700700 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700701 checkPermission();
702
Mike Lockwood03ca2162010-04-01 08:10:09 -0700703 LocationProviderInterface p = mProvidersByName.get(provider);
704 if (p == null) {
705 throw new IllegalArgumentException("provider=" + provider);
706 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700707
708 boolean result = LocationProvider.propertiesMeetCriteria(
709 p.getName(), p.getProperties(), criteria);
710 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
711 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700712 }
713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700715 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400716 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500717 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 boolean isEnabled = p.isEnabled();
719 String name = p.getName();
720 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 if (isEnabled && !shouldBeEnabled) {
722 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700723 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 } else if (!isEnabled && shouldBeEnabled) {
725 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700726 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700728 }
729 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700730 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
731 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 }
733 }
734
735 private void updateProviderListenersLocked(String provider, boolean enabled) {
736 int listeners = 0;
737
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500738 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700739 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740
741 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
744 if (records != null) {
745 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700746 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 UpdateRecord record = records.get(i);
748 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700749 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
750 if (deadReceivers == null) {
751 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 }
Simon Schoar46866572009-06-10 21:12:10 +0200753 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 }
755 listeners++;
756 }
757 }
758
759 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700760 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 removeUpdatesLocked(deadReceivers.get(i));
762 }
763 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 if (enabled) {
766 p.enable();
767 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700768 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 }
770 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 }
774
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700775 private void applyRequirementsLocked(String provider) {
776 LocationProviderInterface p = mProvidersByName.get(provider);
777 if (p == null) return;
778
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700780 WorkSource worksource = new WorkSource();
781 ProviderRequest providerRequest = new ProviderRequest();
782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700784 for (UpdateRecord record : records) {
785 LocationRequest locationRequest = record.mRequest;
786
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700787 providerRequest.locationRequests.add(locationRequest);
788 if (locationRequest.getInterval() < providerRequest.interval) {
789 providerRequest.reportLocation = true;
790 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700791 }
792 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700793
794 if (providerRequest.reportLocation) {
795 // calculate who to blame for power
796 // This is somewhat arbitrary. We pick a threshold interval
797 // that is slightly higher that the minimum interval, and
798 // spread the blame across all applications with a request
799 // under that threshold.
800 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
801 for (UpdateRecord record : records) {
802 LocationRequest locationRequest = record.mRequest;
803 if (locationRequest.getInterval() <= thresholdInterval) {
804 worksource.add(record.mReceiver.mUid);
805 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700806 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
808 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700809
810 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
811 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 }
813
814 private class UpdateRecord {
815 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700816 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400818 Location mLastFixBroadcast;
819 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820
821 /**
822 * Note: must be constructed with lock held.
823 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700824 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700826 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828
829 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
830 if (records == null) {
831 records = new ArrayList<UpdateRecord>();
832 mRecordsByProvider.put(provider, records);
833 }
834 if (!records.contains(this)) {
835 records.add(this);
836 }
837 }
838
839 /**
840 * Method to be called when a record will no longer be used. Calling this multiple times
841 * must have the same effect as calling it once.
842 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700843 void disposeLocked(boolean removeReceiver) {
844 // remove from mRecordsByProvider
845 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
846 if (globalRecords != null) {
847 globalRecords.remove(this);
848 }
849
850 if (!removeReceiver) return; // the caller will handle the rest
851
852 // remove from Receiver#mUpdateRecords
853 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
854 if (receiverRecords != null) {
855 receiverRecords.remove(this.mProvider);
856
857 // and also remove the Receiver if it has no more update records
858 if (removeReceiver && receiverRecords.size() == 0) {
859 removeUpdatesLocked(mReceiver);
860 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400861 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 }
863
864 @Override
865 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700866 StringBuilder s = new StringBuilder();
867 s.append("UpdateRecord[");
868 s.append(mProvider);
869 s.append(' ').append(mReceiver.mPackageName).append('(');
870 s.append(mReceiver.mUid).append(')');
871 s.append(' ').append(mRequest);
872 s.append(']');
873 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 }
876
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700877 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400878 IBinder binder = listener.asBinder();
879 Receiver receiver = mReceivers.get(binder);
880 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700881 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400882 mReceivers.put(binder, receiver);
883
884 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700885 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400886 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800887 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400888 return null;
889 }
890 }
891 return receiver;
892 }
893
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700894 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400895 Receiver receiver = mReceivers.get(intent);
896 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700897 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400898 mReceivers.put(intent, receiver);
899 }
900 return receiver;
901 }
902
Victoria Lease09016ab2012-09-16 12:33:15 -0700903 private boolean isProviderAllowedByCoarsePermission(String provider) {
904 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
905 return true;
906 }
907 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
908 return true;
909 }
910 if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
911 return true;
912 }
913 return false;
914 }
915
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700916 private String checkPermissionAndRequest(LocationRequest request) {
917 String perm = checkPermission();
918
919 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Victoria Lease09016ab2012-09-16 12:33:15 -0700920 if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
921 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
922 }
923 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 }
931 // throttle
932 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
933 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
934 }
935 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
936 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
937 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700938 }
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();
Victoria Lease09016ab2012-09-16 12:33:15 -07001009 if (name == null) {
1010 throw new IllegalArgumentException("provider name must not be null");
1011 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001012 LocationProviderInterface provider = mProvidersByName.get(name);
1013 if (provider == null) {
1014 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1015 }
1016
1017 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1018 name + " " + request + " from " + packageName + "(" + uid + ")");
1019
1020 UpdateRecord record = new UpdateRecord(name, request, receiver);
1021 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1022 if (oldRecord != null) {
1023 oldRecord.disposeLocked(false);
1024 }
1025
1026 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1027 if (isProviderEnabled) {
1028 applyRequirementsLocked(name);
1029 } else {
1030 // Notify the listener that updates are currently disabled
1031 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 }
1033 }
1034
Nick Pellye0fd6932012-07-11 10:26:13 -07001035 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001036 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1037 String packageName) {
1038 checkPackageName(packageName);
1039 checkPermission();
1040 final int pid = Binder.getCallingPid();
1041 final int uid = Binder.getCallingUid();
1042 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1043
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001044 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001045 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001047 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001048 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001050 } finally {
1051 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 }
1053 }
1054
1055 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001056 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1057
1058 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1059 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1060 synchronized (receiver) {
1061 if (receiver.mPendingBroadcasts > 0) {
1062 decrementPendingBroadcasts();
1063 receiver.mPendingBroadcasts = 0;
1064 }
1065 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 }
1067
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001068 // Record which providers were associated with this listener
1069 HashSet<String> providers = new HashSet<String>();
1070 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1071 if (oldRecords != null) {
1072 // Call dispose() on the obsolete update records.
1073 for (UpdateRecord record : oldRecords.values()) {
1074 record.disposeLocked(false);
1075 }
1076 // Accumulate providers
1077 providers.addAll(oldRecords.keySet());
1078 }
1079
1080 // update provider
1081 for (String provider : providers) {
1082 // If provider is already disabled, don't need to do anything
1083 if (!isAllowedBySettingsLocked(provider)) {
1084 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 }
1086
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001087 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 }
1089 }
1090
Nick Pellye0fd6932012-07-11 10:26:13 -07001091 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001092 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001093 if (D) Log.d(TAG, "getLastLocation: " + request);
1094 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1095 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001096 checkPackageName(packageName);
1097
1098 if (mBlacklist.isBlacklisted(packageName)) {
1099 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1100 packageName);
1101 return null;
1102 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001103
1104 synchronized (mLock) {
1105 // Figure out the provider. Either its explicitly request (deprecated API's),
1106 // or use the fused provider
1107 String name = request.getProvider();
1108 if (name == null) name = LocationManager.FUSED_PROVIDER;
1109 LocationProviderInterface provider = mProvidersByName.get(name);
1110 if (provider == null) return null;
1111
1112 if (!isAllowedBySettingsLocked(name)) return null;
1113
1114 Location location = mLastLocation.get(name);
Victoria Lease09016ab2012-09-16 12:33:15 -07001115 if (location == null) {
1116 return null;
1117 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001118 if (ACCESS_FINE_LOCATION.equals(perm)) {
1119 return location;
1120 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001121 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1122 if (noGPSLocation != null) {
1123 return mLocationFudger.getOrCreate(noGPSLocation);
1124 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001125 }
1126 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001127 return null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001128 }
1129
1130 @Override
1131 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1132 String packageName) {
1133 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001134 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001135 checkPermissionAndRequest(request);
1136 checkPendingIntent(intent);
1137 checkPackageName(packageName);
1138
1139 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1140
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001141 // geo-fence manager uses the public location API, need to clear identity
1142 int uid = Binder.getCallingUid();
1143 long identity = Binder.clearCallingIdentity();
1144 try {
1145 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1146 } finally {
1147 Binder.restoreCallingIdentity(identity);
1148 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001149 }
1150
1151 @Override
1152 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001153 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001154 checkPendingIntent(intent);
1155 checkPackageName(packageName);
1156
1157 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1158
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001159 // geo-fence manager uses the public location API, need to clear identity
1160 long identity = Binder.clearCallingIdentity();
1161 try {
1162 mGeofenceManager.removeFence(geofence, intent);
1163 } finally {
1164 Binder.restoreCallingIdentity(identity);
1165 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001166 }
1167
1168
1169 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001170 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001171 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 return false;
1173 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001174 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 PackageManager.PERMISSION_GRANTED) {
1176 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1177 }
1178
1179 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001180 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001182 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 return false;
1184 }
1185 return true;
1186 }
1187
Nick Pellye0fd6932012-07-11 10:26:13 -07001188 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001190 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001191 try {
1192 mGpsStatusProvider.removeGpsStatusListener(listener);
1193 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001194 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 }
1197 }
1198
Nick Pellye0fd6932012-07-11 10:26:13 -07001199 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001201 if (provider == null) {
1202 // throw NullPointerException to remain compatible with previous implementation
1203 throw new NullPointerException();
1204 }
1205
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001206 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001208 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001209 != PackageManager.PERMISSION_GRANTED)) {
1210 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1211 }
1212
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001213 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001214 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001215 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001216
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001217 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 }
1219 }
1220
Nick Pellye0fd6932012-07-11 10:26:13 -07001221 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001223 if (Binder.getCallingUid() != Process.myUid()) {
1224 throw new SecurityException(
1225 "calling sendNiResponse from outside of the system is not allowed");
1226 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001227 try {
1228 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001229 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001230 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001231 return false;
1232 }
1233 }
1234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001236 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001237 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 * accessed by the caller
1239 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001240 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001241 public ProviderProperties getProviderProperties(String provider) {
1242 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001244 LocationProviderInterface p;
1245 synchronized (mLock) {
1246 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 }
1248
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001249 if (p == null) return null;
1250 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 }
1252
Nick Pellye0fd6932012-07-11 10:26:13 -07001253 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001255 checkPermission();
1256 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1257
1258 synchronized (mLock) {
1259 LocationProviderInterface p = mProvidersByName.get(provider);
1260 if (p == null) return false;
1261
1262 return isAllowedBySettingsLocked(provider);
1263 }
1264 }
1265
1266 private void checkCallerIsProvider() {
1267 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1268 == PackageManager.PERMISSION_GRANTED) {
1269 return;
1270 }
1271
1272 // Previously we only used the INSTALL_LOCATION_PROVIDER
1273 // check. But that is system or signature
1274 // protection level which is not flexible enough for
1275 // providers installed oustide the system image. So
1276 // also allow providers with a UID matching the
1277 // currently bound package name
1278
1279 int uid = Binder.getCallingUid();
1280
1281 if (mGeocodeProvider != null) {
1282 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1283 }
1284 for (LocationProviderProxy proxy : mProxyProviders) {
1285 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1286 }
1287 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1288 "or UID of a currently bound location provider");
1289 }
1290
1291 private boolean doesPackageHaveUid(int uid, String packageName) {
1292 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 return false;
1294 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001295 try {
1296 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1297 if (appInfo.uid != uid) {
1298 return false;
1299 }
1300 } catch (NameNotFoundException e) {
1301 return false;
1302 }
1303 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 }
1305
Nick Pellye0fd6932012-07-11 10:26:13 -07001306 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001307 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001308 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001309
Nick Pelly2eeeec22012-07-18 13:13:37 -07001310 if (!location.isComplete()) {
1311 Log.w(TAG, "Dropping incomplete location: " + location);
1312 return;
1313 }
1314
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001315 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1316 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001317 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001318 mLocationHandler.sendMessageAtFrontOfQueue(m);
1319 }
1320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321
1322 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1323 // Always broadcast the first update
1324 if (lastLoc == null) {
1325 return true;
1326 }
1327
Nick Pellyf1be6862012-05-15 10:53:42 -07001328 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001329 long minTime = record.mRequest.getFastestInterval();
Nick Pelly2eeeec22012-07-18 13:13:37 -07001330 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001331 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 return false;
1333 }
1334
1335 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001336 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 if (minDistance > 0.0) {
1338 if (loc.distanceTo(lastLoc) <= minDistance) {
1339 return false;
1340 }
1341 }
1342
1343 return true;
1344 }
1345
Mike Lockwooda4903f22010-02-17 06:42:23 -05001346 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001347 if (D) Log.d(TAG, "incoming location: " + location);
1348
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001349 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001350 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001352 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001354 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001355 if (p == null) return;
1356
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001357 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001358 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1359 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001360 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001361 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001362 lastLocation = new Location(provider);
1363 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001364 } else {
1365 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1366 if (noGPSLocation == null && lastNoGPSLocation != null) {
1367 // New location has no no-GPS location: adopt last no-GPS location. This is set
1368 // directly into location because we do not want to notify COARSE clients.
1369 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1370 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001371 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001372 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373
Victoria Lease09016ab2012-09-16 12:33:15 -07001374 // Fetch coarse location
1375 Location coarseLocation = null;
1376 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1377 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1378 }
1379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001380 // Fetch latest status update time
1381 long newStatusUpdateTime = p.getStatusUpdateTime();
1382
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001383 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 Bundle extras = new Bundle();
1385 int status = p.getStatus(extras);
1386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001388 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001391 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001393 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001394
1395 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1396 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1397 receiver.mPackageName);
1398 continue;
1399 }
1400
Victoria Lease09016ab2012-09-16 12:33:15 -07001401 Location notifyLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001402 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001403 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001404 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001405 notifyLocation = coarseLocation; // use coarse location if available
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001406 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001407 if (notifyLocation != null) {
1408 Location lastLoc = r.mLastFixBroadcast;
1409 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1410 if (lastLoc == null) {
1411 lastLoc = new Location(notifyLocation);
1412 r.mLastFixBroadcast = lastLoc;
1413 } else {
1414 lastLoc.set(notifyLocation);
1415 }
1416 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1417 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1418 receiverDead = true;
1419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 }
1421 }
1422
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001423 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001425 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001427 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001429 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001430 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001431 }
1432 }
1433
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001434 // track expired records
1435 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1436 if (deadUpdateRecords == null) {
1437 deadUpdateRecords = new ArrayList<UpdateRecord>();
1438 }
1439 deadUpdateRecords.add(r);
1440 }
1441 // track dead receivers
1442 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001443 if (deadReceivers == null) {
1444 deadReceivers = new ArrayList<Receiver>();
1445 }
1446 if (!deadReceivers.contains(receiver)) {
1447 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 }
1449 }
1450 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001451
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001452 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001454 for (Receiver receiver : deadReceivers) {
1455 removeUpdatesLocked(receiver);
1456 }
1457 }
1458 if (deadUpdateRecords != null) {
1459 for (UpdateRecord r : deadUpdateRecords) {
1460 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 }
1462 }
1463 }
1464
1465 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 @Override
1467 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001468 switch (msg.what) {
1469 case MSG_LOCATION_CHANGED:
1470 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1471 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 }
1473 }
1474 }
1475
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001476 private void handleLocationChanged(Location location, boolean passive) {
1477 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001478
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001479 if (!passive) {
1480 // notify passive provider of the new location
1481 mPassiveProvider.updateLocation(location);
1482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001484 synchronized (mLock) {
1485 if (isAllowedBySettingsLocked(provider)) {
1486 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001487 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490
Mike Lockwoode97ae402010-09-29 15:23:46 -04001491 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1492 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001493 public void onPackageDisappeared(String packageName, int reason) {
1494 // remove all receivers associated with this package name
1495 synchronized (mLock) {
1496 ArrayList<Receiver> deadReceivers = null;
1497
1498 for (Receiver receiver : mReceivers.values()) {
1499 if (receiver.mPackageName.equals(packageName)) {
1500 if (deadReceivers == null) {
1501 deadReceivers = new ArrayList<Receiver>();
1502 }
1503 deadReceivers.add(receiver);
1504 }
1505 }
1506
1507 // perform removal outside of mReceivers loop
1508 if (deadReceivers != null) {
1509 for (Receiver receiver : deadReceivers) {
1510 removeUpdatesLocked(receiver);
1511 }
1512 }
1513 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001514 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001515 };
1516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 // Wake locks
1518
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001519 private void incrementPendingBroadcasts() {
1520 synchronized (mWakeLock) {
1521 if (mPendingBroadcasts++ == 0) {
1522 try {
1523 mWakeLock.acquire();
1524 log("Acquired wakelock");
1525 } catch (Exception e) {
1526 // This is to catch a runtime exception thrown when we try to release an
1527 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001528 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001529 }
1530 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001531 }
1532 }
1533
1534 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001535 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001536 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001537 try {
1538 // Release wake lock
1539 if (mWakeLock.isHeld()) {
1540 mWakeLock.release();
1541 log("Released wakelock");
1542 } else {
1543 log("Can't release wakelock again!");
1544 }
1545 } catch (Exception e) {
1546 // This is to catch a runtime exception thrown when we try to release an
1547 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001548 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001549 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001550 }
1551 }
1552 }
1553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 // Geocoder
1555
Nick Pellye0fd6932012-07-11 10:26:13 -07001556 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001557 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001558 return mGeocodeProvider != null;
1559 }
1560
Nick Pellye0fd6932012-07-11 10:26:13 -07001561 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001563 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001564 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001565 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1566 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001568 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 }
1570
Mike Lockwooda55c3212009-04-15 11:10:11 -04001571
Nick Pellye0fd6932012-07-11 10:26:13 -07001572 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001574 double lowerLeftLatitude, double lowerLeftLongitude,
1575 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001576 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001577
1578 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001579 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1580 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1581 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001583 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 }
1585
1586 // Mock Providers
1587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 private void checkMockPermissionsSafe() {
1589 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1590 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1591 if (!allowMocks) {
1592 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1593 }
1594
1595 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1596 PackageManager.PERMISSION_GRANTED) {
1597 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 }
1600
Nick Pellye0fd6932012-07-11 10:26:13 -07001601 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001602 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 checkMockPermissionsSafe();
1604
Mike Lockwooda4903f22010-02-17 06:42:23 -05001605 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1606 throw new IllegalArgumentException("Cannot mock the passive location provider");
1607 }
1608
Mike Lockwood86328a92009-10-23 08:38:25 -04001609 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001610 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001611 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001612 // remove the real provider if we are replacing GPS or network provider
1613 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001614 || LocationManager.NETWORK_PROVIDER.equals(name)
1615 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001616 LocationProviderInterface p = mProvidersByName.get(name);
1617 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001618 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001619 }
1620 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001621 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1623 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001624 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001625 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001626 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 updateProvidersLocked();
1628 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001629 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 }
1631
Nick Pellye0fd6932012-07-11 10:26:13 -07001632 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 public void removeTestProvider(String provider) {
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 Lockwood86328a92009-10-23 08:38:25 -04001640 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001641 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001642 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001643
1644 // reinstate real provider if available
1645 LocationProviderInterface realProvider = mRealProviders.get(provider);
1646 if (realProvider != null) {
1647 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001648 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001649 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001651 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 }
1653 }
1654
Nick Pellye0fd6932012-07-11 10:26:13 -07001655 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 public void setTestProviderLocation(String provider, Location loc) {
1657 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001658 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001659 MockProvider mockProvider = mMockProviders.get(provider);
1660 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1662 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001663 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1664 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001665 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001666 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 }
1668 }
1669
Nick Pellye0fd6932012-07-11 10:26:13 -07001670 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 public void clearTestProviderLocation(String provider) {
1672 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001673 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001674 MockProvider mockProvider = mMockProviders.get(provider);
1675 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1677 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001678 mockProvider.clearLocation();
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 setTestProviderEnabled(String provider, boolean enabled) {
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 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001692 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 mEnabledProviders.add(provider);
1694 mDisabledProviders.remove(provider);
1695 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001696 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 mEnabledProviders.remove(provider);
1698 mDisabledProviders.add(provider);
1699 }
1700 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001701 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 }
1703 }
1704
Nick Pellye0fd6932012-07-11 10:26:13 -07001705 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 public void clearTestProviderEnabled(String provider) {
1707 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001708 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001709 MockProvider mockProvider = mMockProviders.get(provider);
1710 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1712 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001713 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 mEnabledProviders.remove(provider);
1715 mDisabledProviders.remove(provider);
1716 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001717 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 }
1719 }
1720
Nick Pellye0fd6932012-07-11 10:26:13 -07001721 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1723 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001724 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001725 MockProvider mockProvider = mMockProviders.get(provider);
1726 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1728 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001729 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 }
1731 }
1732
Nick Pellye0fd6932012-07-11 10:26:13 -07001733 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 public void clearTestProviderStatus(String provider) {
1735 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001736 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001737 MockProvider mockProvider = mMockProviders.get(provider);
1738 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1740 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001741 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 }
1743 }
1744
1745 private void log(String log) {
1746 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001747 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 }
1749 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001750
1751 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1753 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1754 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001755 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 + Binder.getCallingPid()
1757 + ", uid=" + Binder.getCallingUid());
1758 return;
1759 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001760
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001761 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001764 for (Receiver receiver : mReceivers.values()) {
1765 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001768 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1769 pw.println(" " + entry.getKey() + ":");
1770 for (UpdateRecord record : entry.getValue()) {
1771 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 }
1773 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001775 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1776 String provider = entry.getKey();
1777 Location location = entry.getValue();
1778 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001780
Nick Pellye0fd6932012-07-11 10:26:13 -07001781 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 if (mEnabledProviders.size() > 0) {
1784 pw.println(" Enabled Providers:");
1785 for (String i : mEnabledProviders) {
1786 pw.println(" " + i);
1787 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 }
1790 if (mDisabledProviders.size() > 0) {
1791 pw.println(" Disabled Providers:");
1792 for (String i : mDisabledProviders) {
1793 pw.println(" " + i);
1794 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001796 pw.append(" ");
1797 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 if (mMockProviders.size() > 0) {
1799 pw.println(" Mock Providers:");
1800 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001801 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 }
1803 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001804
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001805 pw.append(" fudger: ");
1806 mLocationFudger.dump(fd, pw, args);
1807
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001808 if (args.length > 0 && "short".equals(args[0])) {
1809 return;
1810 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001811 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001812 pw.print(provider.getName() + " Internal State");
1813 if (provider instanceof LocationProviderProxy) {
1814 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1815 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001816 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001817 pw.println(":");
1818 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 }
1821 }
1822}