blob: 37dae35e08c7281439430b1565dee15533321924 [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();
213 mLocationFudger = new LocationFudger();
214
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" +
591 "ACCESS_FINE_LOCATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 }
593
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700594 /**
595 * Returns all providers by name, including passive, but excluding
596 * fused.
597 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700598 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700600 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700602 ArrayList<String> out;
603 synchronized (mLock) {
604 out = new ArrayList<String>(mProviders.size());
605 for (LocationProviderInterface provider : mProviders) {
606 String name = provider.getName();
607 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700608 continue;
609 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 out.add(name);
611 }
612 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700613
614 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 return out;
616 }
617
Mike Lockwood03ca2162010-04-01 08:10:09 -0700618 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700619 * Return all providers by name, that match criteria and are optionally
620 * enabled.
621 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700622 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700623 @Override
624 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
625 checkPermission();
Mike Lockwood03ca2162010-04-01 08:10:09 -0700626
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700627 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700628 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700629 out = new ArrayList<String>(mProviders.size());
630 for (LocationProviderInterface provider : mProviders) {
631 String name = provider.getName();
632 if (LocationManager.FUSED_PROVIDER.equals(name)) {
633 continue;
634 }
635 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
636 continue;
637 }
638 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
639 name, provider.getProperties(), criteria)) {
640 continue;
641 }
642 out.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700643 }
644 }
645
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700646 if (D) Log.d(TAG, "getProviders()=" + out);
647 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700648 }
649
650 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700651 * Return the name of the best provider given a Criteria object.
652 * This method has been deprecated from the public API,
653 * and the whole LoactionProvider (including #meetsCriteria)
654 * has been deprecated as well. So this method now uses
655 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700656 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700657 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700658 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700659 String result = null;
660 checkPermission();
661
662 List<String> providers = getProviders(criteria, enabledOnly);
663 if (providers.size() < 1) {
664 result = pickBest(providers);
665 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
666 return result;
667 }
668 providers = getProviders(null, enabledOnly);
669 if (providers.size() >= 1) {
670 result = pickBest(providers);
671 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
672 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700673 }
674
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700675 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700676 return null;
677 }
678
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700679 private String pickBest(List<String> providers) {
680 if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
681 return LocationManager.NETWORK_PROVIDER;
682 } else if (providers.contains(LocationManager.GPS_PROVIDER)) {
683 return LocationManager.GPS_PROVIDER;
684 } else {
685 return providers.get(0);
686 }
687 }
688
Nick Pellye0fd6932012-07-11 10:26:13 -0700689 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700690 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700691 checkPermission();
692
Mike Lockwood03ca2162010-04-01 08:10:09 -0700693 LocationProviderInterface p = mProvidersByName.get(provider);
694 if (p == null) {
695 throw new IllegalArgumentException("provider=" + provider);
696 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700697
698 boolean result = LocationProvider.propertiesMeetCriteria(
699 p.getName(), p.getProperties(), criteria);
700 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
701 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700702 }
703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700705 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400706 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500707 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 boolean isEnabled = p.isEnabled();
709 String name = p.getName();
710 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 if (isEnabled && !shouldBeEnabled) {
712 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700713 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 } else if (!isEnabled && shouldBeEnabled) {
715 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700716 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700718 }
719 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700720 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
721 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 }
723 }
724
725 private void updateProviderListenersLocked(String provider, boolean enabled) {
726 int listeners = 0;
727
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500728 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700729 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730
731 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
734 if (records != null) {
735 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700736 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 UpdateRecord record = records.get(i);
738 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700739 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
740 if (deadReceivers == null) {
741 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 }
Simon Schoar46866572009-06-10 21:12:10 +0200743 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 }
745 listeners++;
746 }
747 }
748
749 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700750 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 removeUpdatesLocked(deadReceivers.get(i));
752 }
753 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700754
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 if (enabled) {
756 p.enable();
757 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700758 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 }
760 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 }
764
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700765 private void applyRequirementsLocked(String provider) {
766 LocationProviderInterface p = mProvidersByName.get(provider);
767 if (p == null) return;
768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700770 WorkSource worksource = new WorkSource();
771 ProviderRequest providerRequest = new ProviderRequest();
772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700774 for (UpdateRecord record : records) {
775 LocationRequest locationRequest = record.mRequest;
776
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700777 providerRequest.locationRequests.add(locationRequest);
778 if (locationRequest.getInterval() < providerRequest.interval) {
779 providerRequest.reportLocation = true;
780 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700781 }
782 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700783
784 if (providerRequest.reportLocation) {
785 // calculate who to blame for power
786 // This is somewhat arbitrary. We pick a threshold interval
787 // that is slightly higher that the minimum interval, and
788 // spread the blame across all applications with a request
789 // under that threshold.
790 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
791 for (UpdateRecord record : records) {
792 LocationRequest locationRequest = record.mRequest;
793 if (locationRequest.getInterval() <= thresholdInterval) {
794 worksource.add(record.mReceiver.mUid);
795 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700796 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 }
798 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700799
800 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
801 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 }
803
804 private class UpdateRecord {
805 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700806 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400808 Location mLastFixBroadcast;
809 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810
811 /**
812 * Note: must be constructed with lock held.
813 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700814 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700816 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818
819 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
820 if (records == null) {
821 records = new ArrayList<UpdateRecord>();
822 mRecordsByProvider.put(provider, records);
823 }
824 if (!records.contains(this)) {
825 records.add(this);
826 }
827 }
828
829 /**
830 * Method to be called when a record will no longer be used. Calling this multiple times
831 * must have the same effect as calling it once.
832 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700833 void disposeLocked(boolean removeReceiver) {
834 // remove from mRecordsByProvider
835 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
836 if (globalRecords != null) {
837 globalRecords.remove(this);
838 }
839
840 if (!removeReceiver) return; // the caller will handle the rest
841
842 // remove from Receiver#mUpdateRecords
843 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
844 if (receiverRecords != null) {
845 receiverRecords.remove(this.mProvider);
846
847 // and also remove the Receiver if it has no more update records
848 if (removeReceiver && receiverRecords.size() == 0) {
849 removeUpdatesLocked(mReceiver);
850 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400851 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 }
853
854 @Override
855 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700856 StringBuilder s = new StringBuilder();
857 s.append("UpdateRecord[");
858 s.append(mProvider);
859 s.append(' ').append(mReceiver.mPackageName).append('(');
860 s.append(mReceiver.mUid).append(')');
861 s.append(' ').append(mRequest);
862 s.append(']');
863 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 }
866
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700867 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400868 IBinder binder = listener.asBinder();
869 Receiver receiver = mReceivers.get(binder);
870 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700871 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400872 mReceivers.put(binder, receiver);
873
874 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700875 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400876 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800877 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400878 return null;
879 }
880 }
881 return receiver;
882 }
883
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700884 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400885 Receiver receiver = mReceivers.get(intent);
886 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700887 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400888 mReceivers.put(intent, receiver);
889 }
890 return receiver;
891 }
892
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700893 private String checkPermissionAndRequest(LocationRequest request) {
894 String perm = checkPermission();
895
896 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700897 switch (request.getQuality()) {
898 case LocationRequest.ACCURACY_FINE:
899 request.setQuality(LocationRequest.ACCURACY_BLOCK);
900 break;
901 case LocationRequest.POWER_HIGH:
902 request.setQuality(LocationRequest.POWER_LOW);
903 break;
904 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700905 // throttle
906 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
907 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
908 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700909 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
910 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
911 }
912 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700913 // make getFastestInterval() the minimum of interval and fastest interval
914 if (request.getFastestInterval() > request.getInterval()) {
915 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400916 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700917 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400918 }
919
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700920 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700921 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700922 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700923 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700924 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700925 String[] packages = mPackageManager.getPackagesForUid(uid);
926 if (packages == null) {
927 throw new SecurityException("invalid UID " + uid);
928 }
929 for (String pkg : packages) {
930 if (packageName.equals(pkg)) return;
931 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700932 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700933 }
934
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700935 private void checkPendingIntent(PendingIntent intent) {
936 if (intent == null) {
937 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700938 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700939 }
940
941 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
942 int pid, int uid, String packageName) {
943 if (intent == null && listener == null) {
944 throw new IllegalArgumentException("need eiter listener or intent");
945 } else if (intent != null && listener != null) {
946 throw new IllegalArgumentException("cannot register both listener and intent");
947 } else if (intent != null) {
948 checkPendingIntent(intent);
949 return getReceiver(intent, pid, uid, packageName);
950 } else {
951 return getReceiver(listener, pid, uid, packageName);
952 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700953 }
954
Nick Pellye0fd6932012-07-11 10:26:13 -0700955 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700956 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
957 PendingIntent intent, String packageName) {
958 if (request == null) request = DEFAULT_LOCATION_REQUEST;
959 checkPackageName(packageName);
960 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700962 final int pid = Binder.getCallingPid();
963 final int uid = Binder.getCallingUid();
964 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965
Nick Pelly2b7a0d02012-08-17 15:09:44 -0700966 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 long identity = Binder.clearCallingIdentity();
968 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700969 synchronized (mLock) {
970 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400971 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 } finally {
973 Binder.restoreCallingIdentity(identity);
974 }
975 }
976
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700977 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
978 int pid, int uid, String packageName) {
979 // Figure out the provider. Either its explicitly request (legacy use cases), or
980 // use the fused provider
981 if (request == null) request = DEFAULT_LOCATION_REQUEST;
982 String name = request.getProvider();
983 if (name == null) name = LocationManager.FUSED_PROVIDER;
984 LocationProviderInterface provider = mProvidersByName.get(name);
985 if (provider == null) {
986 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
987 }
988
989 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
990 name + " " + request + " from " + packageName + "(" + uid + ")");
991
992 UpdateRecord record = new UpdateRecord(name, request, receiver);
993 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
994 if (oldRecord != null) {
995 oldRecord.disposeLocked(false);
996 }
997
998 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
999 if (isProviderEnabled) {
1000 applyRequirementsLocked(name);
1001 } else {
1002 // Notify the listener that updates are currently disabled
1003 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 }
1005 }
1006
Nick Pellye0fd6932012-07-11 10:26:13 -07001007 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001008 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1009 String packageName) {
1010 checkPackageName(packageName);
1011 checkPermission();
1012 final int pid = Binder.getCallingPid();
1013 final int uid = Binder.getCallingUid();
1014 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1015
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001016 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001017 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001019 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001020 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001022 } finally {
1023 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 }
1025 }
1026
1027 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001028 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1029
1030 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1031 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1032 synchronized (receiver) {
1033 if (receiver.mPendingBroadcasts > 0) {
1034 decrementPendingBroadcasts();
1035 receiver.mPendingBroadcasts = 0;
1036 }
1037 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 }
1039
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001040 // Record which providers were associated with this listener
1041 HashSet<String> providers = new HashSet<String>();
1042 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1043 if (oldRecords != null) {
1044 // Call dispose() on the obsolete update records.
1045 for (UpdateRecord record : oldRecords.values()) {
1046 record.disposeLocked(false);
1047 }
1048 // Accumulate providers
1049 providers.addAll(oldRecords.keySet());
1050 }
1051
1052 // update provider
1053 for (String provider : providers) {
1054 // If provider is already disabled, don't need to do anything
1055 if (!isAllowedBySettingsLocked(provider)) {
1056 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 }
1058
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001059 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 }
1061 }
1062
Nick Pellye0fd6932012-07-11 10:26:13 -07001063 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001064 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001065 if (D) Log.d(TAG, "getLastLocation: " + request);
1066 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1067 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001068 checkPackageName(packageName);
1069
1070 if (mBlacklist.isBlacklisted(packageName)) {
1071 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1072 packageName);
1073 return null;
1074 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001075
1076 synchronized (mLock) {
1077 // Figure out the provider. Either its explicitly request (deprecated API's),
1078 // or use the fused provider
1079 String name = request.getProvider();
1080 if (name == null) name = LocationManager.FUSED_PROVIDER;
1081 LocationProviderInterface provider = mProvidersByName.get(name);
1082 if (provider == null) return null;
1083
1084 if (!isAllowedBySettingsLocked(name)) return null;
1085
1086 Location location = mLastLocation.get(name);
1087 if (ACCESS_FINE_LOCATION.equals(perm)) {
1088 return location;
1089 } else {
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001090 return mLocationFudger.getOrCreate(location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001091 }
1092 }
1093 }
1094
1095 @Override
1096 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1097 String packageName) {
1098 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1099 checkPermissionAndRequest(request);
1100 checkPendingIntent(intent);
1101 checkPackageName(packageName);
1102
1103 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1104
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001105 // geo-fence manager uses the public location API, need to clear identity
1106 int uid = Binder.getCallingUid();
1107 long identity = Binder.clearCallingIdentity();
1108 try {
1109 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1110 } finally {
1111 Binder.restoreCallingIdentity(identity);
1112 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001113 }
1114
1115 @Override
1116 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1117 checkPermission();
1118 checkPendingIntent(intent);
1119 checkPackageName(packageName);
1120
1121 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1122
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001123 // geo-fence manager uses the public location API, need to clear identity
1124 long identity = Binder.clearCallingIdentity();
1125 try {
1126 mGeofenceManager.removeFence(geofence, intent);
1127 } finally {
1128 Binder.restoreCallingIdentity(identity);
1129 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001130 }
1131
1132
1133 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001135 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 return false;
1137 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001138 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 PackageManager.PERMISSION_GRANTED) {
1140 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1141 }
1142
1143 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001144 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001146 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 return false;
1148 }
1149 return true;
1150 }
1151
Nick Pellye0fd6932012-07-11 10:26:13 -07001152 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001154 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001155 try {
1156 mGpsStatusProvider.removeGpsStatusListener(listener);
1157 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001158 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 }
1161 }
1162
Nick Pellye0fd6932012-07-11 10:26:13 -07001163 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001165 if (provider == null) {
1166 // throw NullPointerException to remain compatible with previous implementation
1167 throw new NullPointerException();
1168 }
1169
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001170 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001172 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 != PackageManager.PERMISSION_GRANTED)) {
1174 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1175 }
1176
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001177 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001178 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001179 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001180
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001181 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 }
1183 }
1184
Nick Pellye0fd6932012-07-11 10:26:13 -07001185 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001186 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001187 if (Binder.getCallingUid() != Process.myUid()) {
1188 throw new SecurityException(
1189 "calling sendNiResponse from outside of the system is not allowed");
1190 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001191 try {
1192 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001193 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001194 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001195 return false;
1196 }
1197 }
1198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001200 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001201 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 * accessed by the caller
1203 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001204 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001205 public ProviderProperties getProviderProperties(String provider) {
1206 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001208 LocationProviderInterface p;
1209 synchronized (mLock) {
1210 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 }
1212
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001213 if (p == null) return null;
1214 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 }
1216
Nick Pellye0fd6932012-07-11 10:26:13 -07001217 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001219 checkPermission();
1220 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1221
1222 synchronized (mLock) {
1223 LocationProviderInterface p = mProvidersByName.get(provider);
1224 if (p == null) return false;
1225
1226 return isAllowedBySettingsLocked(provider);
1227 }
1228 }
1229
1230 private void checkCallerIsProvider() {
1231 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1232 == PackageManager.PERMISSION_GRANTED) {
1233 return;
1234 }
1235
1236 // Previously we only used the INSTALL_LOCATION_PROVIDER
1237 // check. But that is system or signature
1238 // protection level which is not flexible enough for
1239 // providers installed oustide the system image. So
1240 // also allow providers with a UID matching the
1241 // currently bound package name
1242
1243 int uid = Binder.getCallingUid();
1244
1245 if (mGeocodeProvider != null) {
1246 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1247 }
1248 for (LocationProviderProxy proxy : mProxyProviders) {
1249 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1250 }
1251 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1252 "or UID of a currently bound location provider");
1253 }
1254
1255 private boolean doesPackageHaveUid(int uid, String packageName) {
1256 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 return false;
1258 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001259 try {
1260 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1261 if (appInfo.uid != uid) {
1262 return false;
1263 }
1264 } catch (NameNotFoundException e) {
1265 return false;
1266 }
1267 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 }
1269
Nick Pellye0fd6932012-07-11 10:26:13 -07001270 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001271 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001272 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001273
Nick Pelly2eeeec22012-07-18 13:13:37 -07001274 if (!location.isComplete()) {
1275 Log.w(TAG, "Dropping incomplete location: " + location);
1276 return;
1277 }
1278
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001279 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1280 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001281 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001282 mLocationHandler.sendMessageAtFrontOfQueue(m);
1283 }
1284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285
1286 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1287 // Always broadcast the first update
1288 if (lastLoc == null) {
1289 return true;
1290 }
1291
Nick Pellyf1be6862012-05-15 10:53:42 -07001292 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001293 long minTime = record.mRequest.getFastestInterval();
Nick Pelly2eeeec22012-07-18 13:13:37 -07001294 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001295 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 return false;
1297 }
1298
1299 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001300 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 if (minDistance > 0.0) {
1302 if (loc.distanceTo(lastLoc) <= minDistance) {
1303 return false;
1304 }
1305 }
1306
1307 return true;
1308 }
1309
Mike Lockwooda4903f22010-02-17 06:42:23 -05001310 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001311 if (D) Log.d(TAG, "incoming location: " + location);
1312
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001313 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001314 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001316 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001318 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001319 if (p == null) return;
1320
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001321 // Add the coarse location as an extra
1322 Location coarse = mLocationFudger.getOrCreate(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324 // Update last known locations
1325 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001326 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001327 lastLocation = new Location(provider);
1328 mLastLocation.put(provider, lastLocation);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001329 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001330 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 // Fetch latest status update time
1333 long newStatusUpdateTime = p.getStatusUpdateTime();
1334
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001335 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 Bundle extras = new Bundle();
1337 int status = p.getStatus(extras);
1338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001340 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001343 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001345 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001346
1347 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1348 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1349 receiver.mPackageName);
1350 continue;
1351 }
1352
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001353 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1354 location = lastLocation; // use fine location
1355 } else {
1356 location = coarse; // use coarse location
1357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001359 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001360 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1361 if (lastLoc == null) {
1362 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001363 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001364 } else {
1365 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001367 if (!receiver.callLocationChangedLocked(location)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001368 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001369 receiverDead = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001370 }
1371 }
1372
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001373 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001374 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1375 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1376
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001377 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001379 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001380 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001381 }
1382 }
1383
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001384 // track expired records
1385 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1386 if (deadUpdateRecords == null) {
1387 deadUpdateRecords = new ArrayList<UpdateRecord>();
1388 }
1389 deadUpdateRecords.add(r);
1390 }
1391 // track dead receivers
1392 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001393 if (deadReceivers == null) {
1394 deadReceivers = new ArrayList<Receiver>();
1395 }
1396 if (!deadReceivers.contains(receiver)) {
1397 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 }
1399 }
1400 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001401
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001402 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001404 for (Receiver receiver : deadReceivers) {
1405 removeUpdatesLocked(receiver);
1406 }
1407 }
1408 if (deadUpdateRecords != null) {
1409 for (UpdateRecord r : deadUpdateRecords) {
1410 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 }
1412 }
1413 }
1414
1415 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 @Override
1417 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001418 switch (msg.what) {
1419 case MSG_LOCATION_CHANGED:
1420 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1421 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 }
1423 }
1424 }
1425
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001426 private void handleLocationChanged(Location location, boolean passive) {
1427 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001428
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001429 if (!passive) {
1430 // notify passive provider of the new location
1431 mPassiveProvider.updateLocation(location);
1432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001434 synchronized (mLock) {
1435 if (isAllowedBySettingsLocked(provider)) {
1436 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001439 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440
Mike Lockwoode97ae402010-09-29 15:23:46 -04001441 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1442 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001443 public void onPackageDisappeared(String packageName, int reason) {
1444 // remove all receivers associated with this package name
1445 synchronized (mLock) {
1446 ArrayList<Receiver> deadReceivers = null;
1447
1448 for (Receiver receiver : mReceivers.values()) {
1449 if (receiver.mPackageName.equals(packageName)) {
1450 if (deadReceivers == null) {
1451 deadReceivers = new ArrayList<Receiver>();
1452 }
1453 deadReceivers.add(receiver);
1454 }
1455 }
1456
1457 // perform removal outside of mReceivers loop
1458 if (deadReceivers != null) {
1459 for (Receiver receiver : deadReceivers) {
1460 removeUpdatesLocked(receiver);
1461 }
1462 }
1463 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001464 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001465 };
1466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 // Wake locks
1468
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001469 private void incrementPendingBroadcasts() {
1470 synchronized (mWakeLock) {
1471 if (mPendingBroadcasts++ == 0) {
1472 try {
1473 mWakeLock.acquire();
1474 log("Acquired wakelock");
1475 } catch (Exception e) {
1476 // This is to catch a runtime exception thrown when we try to release an
1477 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001478 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001479 }
1480 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001481 }
1482 }
1483
1484 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001485 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001486 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001487 try {
1488 // Release wake lock
1489 if (mWakeLock.isHeld()) {
1490 mWakeLock.release();
1491 log("Released wakelock");
1492 } else {
1493 log("Can't release wakelock again!");
1494 }
1495 } catch (Exception e) {
1496 // This is to catch a runtime exception thrown when we try to release an
1497 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001498 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001499 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001500 }
1501 }
1502 }
1503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 // Geocoder
1505
Nick Pellye0fd6932012-07-11 10:26:13 -07001506 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001507 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001508 return mGeocodeProvider != null;
1509 }
1510
Nick Pellye0fd6932012-07-11 10:26:13 -07001511 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001513 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001514 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001515 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1516 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001518 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 }
1520
Mike Lockwooda55c3212009-04-15 11:10:11 -04001521
Nick Pellye0fd6932012-07-11 10:26:13 -07001522 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001524 double lowerLeftLatitude, double lowerLeftLongitude,
1525 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001526 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001527
1528 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001529 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1530 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1531 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001532 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001533 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 }
1535
1536 // Mock Providers
1537
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 private void checkMockPermissionsSafe() {
1539 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1540 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1541 if (!allowMocks) {
1542 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1543 }
1544
1545 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1546 PackageManager.PERMISSION_GRANTED) {
1547 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001548 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 }
1550
Nick Pellye0fd6932012-07-11 10:26:13 -07001551 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001552 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 checkMockPermissionsSafe();
1554
Mike Lockwooda4903f22010-02-17 06:42:23 -05001555 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1556 throw new IllegalArgumentException("Cannot mock the passive location provider");
1557 }
1558
Mike Lockwood86328a92009-10-23 08:38:25 -04001559 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001560 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001561 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001562 // remove the real provider if we are replacing GPS or network provider
1563 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001564 || LocationManager.NETWORK_PROVIDER.equals(name)
1565 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001566 LocationProviderInterface p = mProvidersByName.get(name);
1567 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001568 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001569 }
1570 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001571 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1573 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001574 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001575 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001576 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 updateProvidersLocked();
1578 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001579 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 }
1581
Nick Pellye0fd6932012-07-11 10:26:13 -07001582 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 public void removeTestProvider(String provider) {
1584 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001585 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001586 MockProvider mockProvider = mMockProviders.get(provider);
1587 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1589 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001590 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001591 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001592 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001593
1594 // reinstate real provider if available
1595 LocationProviderInterface realProvider = mRealProviders.get(provider);
1596 if (realProvider != null) {
1597 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001598 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001599 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001601 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 }
1603 }
1604
Nick Pellye0fd6932012-07-11 10:26:13 -07001605 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 public void setTestProviderLocation(String provider, Location loc) {
1607 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001608 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001609 MockProvider mockProvider = mMockProviders.get(provider);
1610 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1612 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001613 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1614 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001615 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001616 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 }
1618 }
1619
Nick Pellye0fd6932012-07-11 10:26:13 -07001620 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 public void clearTestProviderLocation(String provider) {
1622 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001623 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001624 MockProvider mockProvider = mMockProviders.get(provider);
1625 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001626 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1627 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001628 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 }
1630 }
1631
Nick Pellye0fd6932012-07-11 10:26:13 -07001632 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 public void setTestProviderEnabled(String provider, boolean enabled) {
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();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001642 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 mEnabledProviders.add(provider);
1644 mDisabledProviders.remove(provider);
1645 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001646 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 mEnabledProviders.remove(provider);
1648 mDisabledProviders.add(provider);
1649 }
1650 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 clearTestProviderEnabled(String provider) {
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 Lockwood86328a92009-10-23 08:38:25 -04001663 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 mEnabledProviders.remove(provider);
1665 mDisabledProviders.remove(provider);
1666 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001667 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 }
1669 }
1670
Nick Pellye0fd6932012-07-11 10:26:13 -07001671 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1673 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001674 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001675 MockProvider mockProvider = mMockProviders.get(provider);
1676 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1678 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001679 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 }
1681 }
1682
Nick Pellye0fd6932012-07-11 10:26:13 -07001683 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 public void clearTestProviderStatus(String provider) {
1685 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001686 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001687 MockProvider mockProvider = mMockProviders.get(provider);
1688 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1690 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001691 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 }
1693 }
1694
1695 private void log(String log) {
1696 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001697 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 }
1699 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001700
1701 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1703 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1704 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001705 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 + Binder.getCallingPid()
1707 + ", uid=" + Binder.getCallingUid());
1708 return;
1709 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001710
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001711 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001714 for (Receiver receiver : mReceivers.values()) {
1715 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001718 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1719 pw.println(" " + entry.getKey() + ":");
1720 for (UpdateRecord record : entry.getValue()) {
1721 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 }
1723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001725 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1726 String provider = entry.getKey();
1727 Location location = entry.getValue();
1728 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001730
Nick Pellye0fd6932012-07-11 10:26:13 -07001731 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 if (mEnabledProviders.size() > 0) {
1734 pw.println(" Enabled Providers:");
1735 for (String i : mEnabledProviders) {
1736 pw.println(" " + i);
1737 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 }
1740 if (mDisabledProviders.size() > 0) {
1741 pw.println(" Disabled Providers:");
1742 for (String i : mDisabledProviders) {
1743 pw.println(" " + i);
1744 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001746 pw.append(" ");
1747 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 if (mMockProviders.size() > 0) {
1749 pw.println(" Mock Providers:");
1750 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001751 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 }
1753 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001754
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001755 pw.append(" fudger: ");
1756 mLocationFudger.dump(fd, pw, args);
1757
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001758 if (args.length > 0 && "short".equals(args[0])) {
1759 return;
1760 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001761 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001762 pw.print(provider.getName() + " Internal State");
1763 if (provider instanceof LocationProviderProxy) {
1764 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1765 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001766 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001767 pw.println(":");
1768 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001769 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 }
1771 }
1772}