blob: bb005d9ad2c655040976a62dba52fca195d97c9f [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;
Mike Lockwood9637d472009-04-02 21:41:57 -070029import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070031import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050032import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070033import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040035import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.location.ILocationListener;
37import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040038import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.Location;
40import android.location.LocationManager;
41import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070042import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.net.ConnectivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.Binder;
45import android.os.Bundle;
46import android.os.Handler;
47import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070048import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.Message;
50import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070051import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070053import android.os.SystemClock;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070054import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.provider.Settings;
Nick Pellye0fd6932012-07-11 10:26:13 -070056import android.provider.Settings.NameValueTable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080058import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059
Mike Lockwoode97ae402010-09-29 15:23:46 -040060import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070061import com.android.internal.location.ProviderProperties;
62import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040063import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070064import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040065import com.android.server.location.GpsLocationProvider;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070066import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040067import com.android.server.location.LocationProviderInterface;
68import com.android.server.location.LocationProviderProxy;
69import com.android.server.location.MockProvider;
70import com.android.server.location.PassiveProvider;
71
72import java.io.FileDescriptor;
73import java.io.PrintWriter;
74import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070075import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040076import java.util.HashMap;
77import java.util.HashSet;
78import java.util.List;
79import java.util.Map;
80import java.util.Observable;
81import java.util.Observer;
82import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
84/**
85 * The service class that manages LocationProviders and issues location
86 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -070088public class LocationManagerService extends ILocationManager.Stub implements Observer, Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070090 public static final boolean D = false;
91
92 private static final String WAKELOCK_KEY = TAG;
93 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 private static final String ACCESS_FINE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070096 android.Manifest.permission.ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 private static final String ACCESS_COARSE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070098 android.Manifest.permission.ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700100 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700102 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400103 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700104 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
105
106 private static final String NETWORK_LOCATION_SERVICE_ACTION =
107 "com.android.location.service.v2.NetworkLocationProvider";
108 private static final String FUSED_LOCATION_SERVICE_ACTION =
109 "com.android.location.service.FusedLocationProvider";
110
111 private static final int MSG_LOCATION_CHANGED = 1;
112
Nick Pellyf1be6862012-05-15 10:53:42 -0700113 // Location Providers may sometimes deliver location updates
114 // slightly faster that requested - provide grace period so
115 // we don't unnecessarily filter events that are otherwise on
116 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700117 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700118
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700119 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
120
121 private final Context mContext;
122
123 // used internally for synchronization
124 private final Object mLock = new Object();
125
126 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700127 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700128 private GeofenceManager mGeofenceManager;
129 private PowerManager.WakeLock mWakeLock;
130 private PackageManager mPackageManager;
131 private GeocoderProxy mGeocodeProvider;
132 private IGpsStatusProvider mGpsStatusProvider;
133 private INetInitiatedListener mNetInitiatedListener;
134 private LocationWorkerHandler mLocationHandler;
135 // track the passive provider for some special cases
136 private PassiveProvider mPassiveProvider;
137
138 // --- fields below are protected by mWakeLock ---
139 private int mPendingBroadcasts;
140
141 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 // Set of providers that are explicitly enabled
143 private final Set<String> mEnabledProviders = new HashSet<String>();
144
145 // Set of providers that are explicitly disabled
146 private final Set<String> mDisabledProviders = new HashSet<String>();
147
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700148 // Mock (test) providers
149 private final HashMap<String, MockProvider> mMockProviders =
150 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700152 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400153 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500156 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700157 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400158
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700159 // real providers, saved here when mocked out
160 private final HashMap<String, LocationProviderInterface> mRealProviders =
161 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700163 // mapping from provider name to provider
164 private final HashMap<String, LocationProviderInterface> mProvidersByName =
165 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 // mapping from provider name to all its UpdateRecords
168 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
169 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700170
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700171 // mapping from provider name to last known location
172 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174 // all providers that operate over proxy, for authorizing incoming location
175 private final ArrayList<LocationProviderProxy> mProxyProviders =
176 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700178 public LocationManagerService(Context context) {
179 super();
180 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800181
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700182 if (D) Log.d(TAG, "Constructed");
183
184 // most startup is deferred until systemReady()
185 }
186
187 public void systemReady() {
188 Thread thread = new Thread(null, this, THREAD_NAME);
189 thread.start();
190 }
191
192 @Override
193 public void run() {
194 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
195 Looper.prepare();
196 mLocationHandler = new LocationWorkerHandler();
197 init();
198 Looper.loop();
199 }
200
201 private void init() {
202 if (D) Log.d(TAG, "init()");
203
204 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
205 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
206 mPackageManager = mContext.getPackageManager();
207
208 synchronized (mLock) {
209 loadProvidersLocked();
210 }
211 mGeofenceManager = new GeofenceManager(mContext);
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700212 mLocationFudger = new LocationFudger();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700213
214 // Register for Network (Wifi or Mobile) updates
215 IntentFilter filter = new IntentFilter();
216 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
217
218 // listen for settings changes
219 ContentResolver resolver = mContext.getContentResolver();
220 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
221 "(" + NameValueTable.NAME + "=?)",
222 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, null);
223 ContentQueryMap query = new ContentQueryMap(settingsCursor, NameValueTable.NAME, true,
224 mLocationHandler);
225 settingsCursor.close();
226 query.addObserver(this);
227 mPackageMonitor.register(mContext, Looper.myLooper(), true);
228 }
229
230 private void loadProvidersLocked() {
231 if (GpsLocationProvider.isSupported()) {
232 // Create a gps location provider
233 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
234 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
235 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
236 addProviderLocked(gpsProvider);
237 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
238 }
239
240 // create a passive location provider, which is always enabled
241 PassiveProvider passiveProvider = new PassiveProvider(this);
242 addProviderLocked(passiveProvider);
243 mEnabledProviders.add(passiveProvider.getName());
244 mPassiveProvider = passiveProvider;
245
246 /*
247 Load package name(s) containing location provider support.
248 These packages can contain services implementing location providers:
249 Geocoder Provider, Network Location Provider, and
250 Fused Location Provider. They will each be searched for
251 service components implementing these providers.
252 The location framework also has support for installation
253 of new location providers at run-time. The new package does not
254 have to be explicitly listed here, however it must have a signature
255 that matches the signature of at least one package on this list.
256 */
257 Resources resources = mContext.getResources();
258 ArrayList<String> providerPackageNames = new ArrayList<String>();
259 String[] pkgs1 = resources.getStringArray(
260 com.android.internal.R.array.config_locationProviderPackageNames);
261 String[] pkgs2 = resources.getStringArray(
262 com.android.internal.R.array.config_overlay_locationProviderPackageNames);
263 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
264 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
265 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
266 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
267
268 // bind to network provider
269 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
270 mContext,
271 LocationManager.NETWORK_PROVIDER,
272 NETWORK_LOCATION_SERVICE_ACTION,
273 providerPackageNames, mLocationHandler);
274 if (networkProvider != null) {
275 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
276 mProxyProviders.add(networkProvider);
277 addProviderLocked(networkProvider);
278 } else {
279 Slog.w(TAG, "no network location provider found");
280 }
281
282 // bind to fused provider
283 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
284 mContext,
285 LocationManager.FUSED_PROVIDER,
286 FUSED_LOCATION_SERVICE_ACTION,
287 providerPackageNames, mLocationHandler);
288 if (fusedLocationProvider != null) {
289 addProviderLocked(fusedLocationProvider);
290 mProxyProviders.add(fusedLocationProvider);
291 mEnabledProviders.add(fusedLocationProvider.getName());
292 } else {
293 Slog.e(TAG, "no fused location provider found",
294 new IllegalStateException("Location service needs a fused location provider"));
295 }
296
297 // bind to geocoder provider
298 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
299 if (mGeocodeProvider == null) {
300 Slog.e(TAG, "no geocoder provider found");
301 }
302
303 updateProvidersLocked();
304 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 /**
307 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
308 * location updates.
309 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700310 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700311 final int mUid; // uid of receiver
312 final int mPid; // pid of receiver
313 final String mPackageName; // package name of receiver
314 final String mPermission; // best permission that receiver has
315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 final ILocationListener mListener;
317 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700319
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400320 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700321
Mike Lockwood48f17512009-04-23 09:12:08 -0700322 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700324 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
325 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700328 if (listener != null) {
329 mKey = listener.asBinder();
330 } else {
331 mKey = intent;
332 }
333 mPermission = checkPermission();
334 mUid = uid;
335 mPid = pid;
336 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 }
338
339 @Override
340 public boolean equals(Object otherObj) {
341 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700342 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 }
344 return false;
345 }
346
347 @Override
348 public int hashCode() {
349 return mKey.hashCode();
350 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 @Override
353 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700354 StringBuilder s = new StringBuilder();
355 s.append("Reciever[");
356 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700358 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700360 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700362 for (String p : mUpdateRecords.keySet()) {
363 s.append(" ").append(mUpdateRecords.get(p).toString());
364 }
365 s.append("]");
366 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 }
368
369 public boolean isListener() {
370 return mListener != null;
371 }
372
373 public boolean isPendingIntent() {
374 return mPendingIntent != null;
375 }
376
377 public ILocationListener getListener() {
378 if (mListener != null) {
379 return mListener;
380 }
381 throw new IllegalStateException("Request for non-existent listener");
382 }
383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
385 if (mListener != null) {
386 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700387 synchronized (this) {
388 // synchronize to ensure incrementPendingBroadcastsLocked()
389 // is called before decrementPendingBroadcasts()
390 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700391 // call this after broadcasting so we do not increment
392 // if we throw an exeption.
393 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700394 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 } catch (RemoteException e) {
396 return false;
397 }
398 } else {
399 Intent statusChanged = new Intent();
400 statusChanged.putExtras(extras);
401 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
402 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700403 synchronized (this) {
404 // synchronize to ensure incrementPendingBroadcastsLocked()
405 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700406 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700407 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700408 // call this after broadcasting so we do not increment
409 // if we throw an exeption.
410 incrementPendingBroadcastsLocked();
411 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 } catch (PendingIntent.CanceledException e) {
413 return false;
414 }
415 }
416 return true;
417 }
418
419 public boolean callLocationChangedLocked(Location location) {
420 if (mListener != null) {
421 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700422 synchronized (this) {
423 // synchronize to ensure incrementPendingBroadcastsLocked()
424 // is called before decrementPendingBroadcasts()
425 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700426 // call this after broadcasting so we do not increment
427 // if we throw an exeption.
428 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 } catch (RemoteException e) {
431 return false;
432 }
433 } else {
434 Intent locationChanged = new Intent();
435 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
436 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700437 synchronized (this) {
438 // synchronize to ensure incrementPendingBroadcastsLocked()
439 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700440 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700441 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700442 // call this after broadcasting so we do not increment
443 // if we throw an exeption.
444 incrementPendingBroadcastsLocked();
445 }
446 } catch (PendingIntent.CanceledException e) {
447 return false;
448 }
449 }
450 return true;
451 }
452
453 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
454 if (mListener != null) {
455 try {
456 synchronized (this) {
457 // synchronize to ensure incrementPendingBroadcastsLocked()
458 // is called before decrementPendingBroadcasts()
459 if (enabled) {
460 mListener.onProviderEnabled(provider);
461 } else {
462 mListener.onProviderDisabled(provider);
463 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700464 // call this after broadcasting so we do not increment
465 // if we throw an exeption.
466 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700467 }
468 } catch (RemoteException e) {
469 return false;
470 }
471 } else {
472 Intent providerIntent = new Intent();
473 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
474 try {
475 synchronized (this) {
476 // synchronize to ensure incrementPendingBroadcastsLocked()
477 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700478 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700479 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700480 // call this after broadcasting so we do not increment
481 // if we throw an exeption.
482 incrementPendingBroadcastsLocked();
483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 } catch (PendingIntent.CanceledException e) {
485 return false;
486 }
487 }
488 return true;
489 }
490
Nick Pellyf1be6862012-05-15 10:53:42 -0700491 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700493 if (D) Log.d(TAG, "Location listener died");
494
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400495 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 removeUpdatesLocked(this);
497 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700498 synchronized (this) {
499 if (mPendingBroadcasts > 0) {
500 LocationManagerService.this.decrementPendingBroadcasts();
501 mPendingBroadcasts = 0;
502 }
503 }
504 }
505
Nick Pellye0fd6932012-07-11 10:26:13 -0700506 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700507 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
508 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400509 synchronized (this) {
510 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700511 }
512 }
513
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400514 // this must be called while synchronized by caller in a synchronized block
515 // containing the sending of the broadcaset
516 private void incrementPendingBroadcastsLocked() {
517 if (mPendingBroadcasts++ == 0) {
518 LocationManagerService.this.incrementPendingBroadcasts();
519 }
520 }
521
522 private void decrementPendingBroadcastsLocked() {
523 if (--mPendingBroadcasts == 0) {
524 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700525 }
526 }
527 }
528
Nick Pellye0fd6932012-07-11 10:26:13 -0700529 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700530 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400531 //Do not use getReceiver here as that will add the ILocationListener to
532 //the receiver list if it is not found. If it is not found then the
533 //LocationListener was removed when it had a pending broadcast and should
534 //not be added back.
535 IBinder binder = listener.asBinder();
536 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700537 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400538 synchronized (receiver) {
539 // so wakelock calls will succeed
540 long identity = Binder.clearCallingIdentity();
541 receiver.decrementPendingBroadcastsLocked();
542 Binder.restoreCallingIdentity(identity);
543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 }
545 }
546
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700547 /** Settings Observer callback */
548 @Override
549 public void update(Observable o, Object arg) {
550 synchronized (mLock) {
551 updateProvidersLocked();
Mike Lockwood9637d472009-04-02 21:41:57 -0700552 }
553 }
554
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700555 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400556 mProviders.add(provider);
557 mProvidersByName.put(provider.getName(), provider);
558 }
559
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700560 private void removeProviderLocked(LocationProviderInterface provider) {
561 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400562 mProviders.remove(provider);
563 mProvidersByName.remove(provider.getName());
564 }
565
Mike Lockwood3d12b512009-04-21 23:25:35 -0700566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 private boolean isAllowedBySettingsLocked(String provider) {
568 if (mEnabledProviders.contains(provider)) {
569 return true;
570 }
571 if (mDisabledProviders.contains(provider)) {
572 return false;
573 }
574 // Use system settings
575 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576
Brad Larson8eb3ea62009-12-29 11:47:55 -0600577 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 }
579
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700580 /**
581 * Throw SecurityException if caller has neither COARSE or FINE.
582 * Otherwise, return the best permission.
583 */
584 private String checkPermission() {
585 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
586 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700587 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700588 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
589 PackageManager.PERMISSION_GRANTED) {
590 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700592
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700593 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
594 "ACCESS_FINE_LOCATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 }
596
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700597 /**
598 * Returns all providers by name, including passive, but excluding
599 * fused.
600 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700601 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700603 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700605 ArrayList<String> out;
606 synchronized (mLock) {
607 out = new ArrayList<String>(mProviders.size());
608 for (LocationProviderInterface provider : mProviders) {
609 String name = provider.getName();
610 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700611 continue;
612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 out.add(name);
614 }
615 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700616
617 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 return out;
619 }
620
Mike Lockwood03ca2162010-04-01 08:10:09 -0700621 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700622 * Return all providers by name, that match criteria and are optionally
623 * enabled.
624 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700625 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700626 @Override
627 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
628 checkPermission();
Mike Lockwood03ca2162010-04-01 08:10:09 -0700629
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700630 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700631 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700632 out = new ArrayList<String>(mProviders.size());
633 for (LocationProviderInterface provider : mProviders) {
634 String name = provider.getName();
635 if (LocationManager.FUSED_PROVIDER.equals(name)) {
636 continue;
637 }
638 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
639 continue;
640 }
641 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
642 name, provider.getProperties(), criteria)) {
643 continue;
644 }
645 out.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700646 }
647 }
648
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700649 if (D) Log.d(TAG, "getProviders()=" + out);
650 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700651 }
652
653 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700654 * Return the name of the best provider given a Criteria object.
655 * This method has been deprecated from the public API,
656 * and the whole LoactionProvider (including #meetsCriteria)
657 * has been deprecated as well. So this method now uses
658 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700659 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700660 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700661 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700662 String result = null;
663 checkPermission();
664
665 List<String> providers = getProviders(criteria, enabledOnly);
666 if (providers.size() < 1) {
667 result = pickBest(providers);
668 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
669 return result;
670 }
671 providers = getProviders(null, enabledOnly);
672 if (providers.size() >= 1) {
673 result = pickBest(providers);
674 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
675 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700676 }
677
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700678 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700679 return null;
680 }
681
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700682 private String pickBest(List<String> providers) {
683 if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
684 return LocationManager.NETWORK_PROVIDER;
685 } else if (providers.contains(LocationManager.GPS_PROVIDER)) {
686 return LocationManager.GPS_PROVIDER;
687 } else {
688 return providers.get(0);
689 }
690 }
691
Nick Pellye0fd6932012-07-11 10:26:13 -0700692 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700693 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700694 checkPermission();
695
Mike Lockwood03ca2162010-04-01 08:10:09 -0700696 LocationProviderInterface p = mProvidersByName.get(provider);
697 if (p == null) {
698 throw new IllegalArgumentException("provider=" + provider);
699 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700700
701 boolean result = LocationProvider.propertiesMeetCriteria(
702 p.getName(), p.getProperties(), criteria);
703 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
704 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700705 }
706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700708 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400709 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500710 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 boolean isEnabled = p.isEnabled();
712 String name = p.getName();
713 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 if (isEnabled && !shouldBeEnabled) {
715 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700716 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 } else if (!isEnabled && shouldBeEnabled) {
718 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700719 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700721 }
722 if (changesMade) {
723 mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 }
725 }
726
727 private void updateProviderListenersLocked(String provider, boolean enabled) {
728 int listeners = 0;
729
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500730 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700731 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732
733 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700734
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
736 if (records != null) {
737 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700738 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 UpdateRecord record = records.get(i);
740 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700741 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
742 if (deadReceivers == null) {
743 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 }
Simon Schoar46866572009-06-10 21:12:10 +0200745 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 }
747 listeners++;
748 }
749 }
750
751 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700752 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 removeUpdatesLocked(deadReceivers.get(i));
754 }
755 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 if (enabled) {
758 p.enable();
759 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700760 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 }
762 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 }
766
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700767 private void applyRequirementsLocked(String provider) {
768 LocationProviderInterface p = mProvidersByName.get(provider);
769 if (p == null) return;
770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700772 WorkSource worksource = new WorkSource();
773 ProviderRequest providerRequest = new ProviderRequest();
774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700776 for (UpdateRecord record : records) {
777 LocationRequest locationRequest = record.mRequest;
778
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700779 providerRequest.locationRequests.add(locationRequest);
780 if (locationRequest.getInterval() < providerRequest.interval) {
781 providerRequest.reportLocation = true;
782 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700783 }
784 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700785
786 if (providerRequest.reportLocation) {
787 // calculate who to blame for power
788 // This is somewhat arbitrary. We pick a threshold interval
789 // that is slightly higher that the minimum interval, and
790 // spread the blame across all applications with a request
791 // under that threshold.
792 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
793 for (UpdateRecord record : records) {
794 LocationRequest locationRequest = record.mRequest;
795 if (locationRequest.getInterval() <= thresholdInterval) {
796 worksource.add(record.mReceiver.mUid);
797 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700798 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 }
800 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700801
802 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
803 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 }
805
806 private class UpdateRecord {
807 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700808 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400810 Location mLastFixBroadcast;
811 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812
813 /**
814 * Note: must be constructed with lock held.
815 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700816 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700818 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820
821 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
822 if (records == null) {
823 records = new ArrayList<UpdateRecord>();
824 mRecordsByProvider.put(provider, records);
825 }
826 if (!records.contains(this)) {
827 records.add(this);
828 }
829 }
830
831 /**
832 * Method to be called when a record will no longer be used. Calling this multiple times
833 * must have the same effect as calling it once.
834 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700835 void disposeLocked(boolean removeReceiver) {
836 // remove from mRecordsByProvider
837 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
838 if (globalRecords != null) {
839 globalRecords.remove(this);
840 }
841
842 if (!removeReceiver) return; // the caller will handle the rest
843
844 // remove from Receiver#mUpdateRecords
845 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
846 if (receiverRecords != null) {
847 receiverRecords.remove(this.mProvider);
848
849 // and also remove the Receiver if it has no more update records
850 if (removeReceiver && receiverRecords.size() == 0) {
851 removeUpdatesLocked(mReceiver);
852 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400853 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
855
856 @Override
857 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700858 StringBuilder s = new StringBuilder();
859 s.append("UpdateRecord[");
860 s.append(mProvider);
861 s.append(' ').append(mReceiver.mPackageName).append('(');
862 s.append(mReceiver.mUid).append(')');
863 s.append(' ').append(mRequest);
864 s.append(']');
865 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 }
868
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700869 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400870 IBinder binder = listener.asBinder();
871 Receiver receiver = mReceivers.get(binder);
872 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700873 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400874 mReceivers.put(binder, receiver);
875
876 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700877 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400878 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800879 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400880 return null;
881 }
882 }
883 return receiver;
884 }
885
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700886 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400887 Receiver receiver = mReceivers.get(intent);
888 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700889 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400890 mReceivers.put(intent, receiver);
891 }
892 return receiver;
893 }
894
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700895 private String checkPermissionAndRequest(LocationRequest request) {
896 String perm = checkPermission();
897
898 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700899 switch (request.getQuality()) {
900 case LocationRequest.ACCURACY_FINE:
901 request.setQuality(LocationRequest.ACCURACY_BLOCK);
902 break;
903 case LocationRequest.POWER_HIGH:
904 request.setQuality(LocationRequest.POWER_LOW);
905 break;
906 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700907 // throttle
908 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
909 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
910 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700911 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
912 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
913 }
914 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700915 // make getFastestInterval() the minimum of interval and fastest interval
916 if (request.getFastestInterval() > request.getInterval()) {
917 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400918 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700919 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400920 }
921
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700922 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700923 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700924 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700925 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700926 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700927 String[] packages = mPackageManager.getPackagesForUid(uid);
928 if (packages == null) {
929 throw new SecurityException("invalid UID " + uid);
930 }
931 for (String pkg : packages) {
932 if (packageName.equals(pkg)) return;
933 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700934 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700935 }
936
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700937 private void checkPendingIntent(PendingIntent intent) {
938 if (intent == null) {
939 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700940 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700941 }
942
943 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
944 int pid, int uid, String packageName) {
945 if (intent == null && listener == null) {
946 throw new IllegalArgumentException("need eiter listener or intent");
947 } else if (intent != null && listener != null) {
948 throw new IllegalArgumentException("cannot register both listener and intent");
949 } else if (intent != null) {
950 checkPendingIntent(intent);
951 return getReceiver(intent, pid, uid, packageName);
952 } else {
953 return getReceiver(listener, pid, uid, packageName);
954 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700955 }
956
Nick Pellye0fd6932012-07-11 10:26:13 -0700957 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700958 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
959 PendingIntent intent, String packageName) {
960 if (request == null) request = DEFAULT_LOCATION_REQUEST;
961 checkPackageName(packageName);
962 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700964 final int pid = Binder.getCallingPid();
965 final int uid = Binder.getCallingUid();
966 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700968 // so wakelock calls will succeed (not totally sure this is still needed)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 long identity = Binder.clearCallingIdentity();
970 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700971 synchronized (mLock) {
972 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400973 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 } finally {
975 Binder.restoreCallingIdentity(identity);
976 }
977 }
978
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700979 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
980 int pid, int uid, String packageName) {
981 // Figure out the provider. Either its explicitly request (legacy use cases), or
982 // use the fused provider
983 if (request == null) request = DEFAULT_LOCATION_REQUEST;
984 String name = request.getProvider();
985 if (name == null) name = LocationManager.FUSED_PROVIDER;
986 LocationProviderInterface provider = mProvidersByName.get(name);
987 if (provider == null) {
988 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
989 }
990
991 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
992 name + " " + request + " from " + packageName + "(" + uid + ")");
993
994 UpdateRecord record = new UpdateRecord(name, request, receiver);
995 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
996 if (oldRecord != null) {
997 oldRecord.disposeLocked(false);
998 }
999
1000 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1001 if (isProviderEnabled) {
1002 applyRequirementsLocked(name);
1003 } else {
1004 // Notify the listener that updates are currently disabled
1005 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 }
1007 }
1008
Nick Pellye0fd6932012-07-11 10:26:13 -07001009 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001010 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1011 String packageName) {
1012 checkPackageName(packageName);
1013 checkPermission();
1014 final int pid = Binder.getCallingPid();
1015 final int uid = Binder.getCallingUid();
1016 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1017
1018 // so wakelock calls will succeed (not totally sure this is still needed)
1019 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001021 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001022 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001024 } finally {
1025 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
1027 }
1028
1029 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001030 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1031
1032 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1033 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1034 synchronized (receiver) {
1035 if (receiver.mPendingBroadcasts > 0) {
1036 decrementPendingBroadcasts();
1037 receiver.mPendingBroadcasts = 0;
1038 }
1039 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 }
1041
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001042 // Record which providers were associated with this listener
1043 HashSet<String> providers = new HashSet<String>();
1044 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1045 if (oldRecords != null) {
1046 // Call dispose() on the obsolete update records.
1047 for (UpdateRecord record : oldRecords.values()) {
1048 record.disposeLocked(false);
1049 }
1050 // Accumulate providers
1051 providers.addAll(oldRecords.keySet());
1052 }
1053
1054 // update provider
1055 for (String provider : providers) {
1056 // If provider is already disabled, don't need to do anything
1057 if (!isAllowedBySettingsLocked(provider)) {
1058 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 }
1060
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001061 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 }
1063 }
1064
Nick Pellye0fd6932012-07-11 10:26:13 -07001065 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001066 public Location getLastLocation(LocationRequest request) {
1067 if (D) Log.d(TAG, "getLastLocation: " + request);
1068 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1069 String perm = checkPermissionAndRequest(request);
1070
1071 synchronized (mLock) {
1072 // Figure out the provider. Either its explicitly request (deprecated API's),
1073 // or use the fused provider
1074 String name = request.getProvider();
1075 if (name == null) name = LocationManager.FUSED_PROVIDER;
1076 LocationProviderInterface provider = mProvidersByName.get(name);
1077 if (provider == null) return null;
1078
1079 if (!isAllowedBySettingsLocked(name)) return null;
1080
1081 Location location = mLastLocation.get(name);
1082 if (ACCESS_FINE_LOCATION.equals(perm)) {
1083 return location;
1084 } else {
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001085 return mLocationFudger.getOrCreate(location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001086 }
1087 }
1088 }
1089
1090 @Override
1091 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1092 String packageName) {
1093 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1094 checkPermissionAndRequest(request);
1095 checkPendingIntent(intent);
1096 checkPackageName(packageName);
1097
1098 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1099
1100 mGeofenceManager.addFence(request, geofence, intent, Binder.getCallingUid(), packageName);
1101 }
1102
1103 @Override
1104 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1105 checkPermission();
1106 checkPendingIntent(intent);
1107 checkPackageName(packageName);
1108
1109 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1110
1111 mGeofenceManager.removeFence(geofence, intent);
1112 }
1113
1114
1115 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001117 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 return false;
1119 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001120 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 PackageManager.PERMISSION_GRANTED) {
1122 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1123 }
1124
1125 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001126 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001128 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 return false;
1130 }
1131 return true;
1132 }
1133
Nick Pellye0fd6932012-07-11 10:26:13 -07001134 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001136 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001137 try {
1138 mGpsStatusProvider.removeGpsStatusListener(listener);
1139 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001140 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 }
1143 }
1144
Nick Pellye0fd6932012-07-11 10:26:13 -07001145 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001147 if (provider == null) {
1148 // throw NullPointerException to remain compatible with previous implementation
1149 throw new NullPointerException();
1150 }
1151
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001152 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001154 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 != PackageManager.PERMISSION_GRANTED)) {
1156 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1157 }
1158
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001159 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001160 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001161 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001162
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001163 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 }
1165 }
1166
Nick Pellye0fd6932012-07-11 10:26:13 -07001167 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001168 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001169 if (Binder.getCallingUid() != Process.myUid()) {
1170 throw new SecurityException(
1171 "calling sendNiResponse from outside of the system is not allowed");
1172 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001173 try {
1174 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001175 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001176 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001177 return false;
1178 }
1179 }
1180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001182 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001183 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 * accessed by the caller
1185 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001186 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001187 public ProviderProperties getProviderProperties(String provider) {
1188 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001190 LocationProviderInterface p;
1191 synchronized (mLock) {
1192 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
1194
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001195 if (p == null) return null;
1196 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 }
1198
Nick Pellye0fd6932012-07-11 10:26:13 -07001199 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001201 checkPermission();
1202 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1203
1204 synchronized (mLock) {
1205 LocationProviderInterface p = mProvidersByName.get(provider);
1206 if (p == null) return false;
1207
1208 return isAllowedBySettingsLocked(provider);
1209 }
1210 }
1211
1212 private void checkCallerIsProvider() {
1213 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1214 == PackageManager.PERMISSION_GRANTED) {
1215 return;
1216 }
1217
1218 // Previously we only used the INSTALL_LOCATION_PROVIDER
1219 // check. But that is system or signature
1220 // protection level which is not flexible enough for
1221 // providers installed oustide the system image. So
1222 // also allow providers with a UID matching the
1223 // currently bound package name
1224
1225 int uid = Binder.getCallingUid();
1226
1227 if (mGeocodeProvider != null) {
1228 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1229 }
1230 for (LocationProviderProxy proxy : mProxyProviders) {
1231 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1232 }
1233 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1234 "or UID of a currently bound location provider");
1235 }
1236
1237 private boolean doesPackageHaveUid(int uid, String packageName) {
1238 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 return false;
1240 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001241 try {
1242 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1243 if (appInfo.uid != uid) {
1244 return false;
1245 }
1246 } catch (NameNotFoundException e) {
1247 return false;
1248 }
1249 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 }
1251
Nick Pellye0fd6932012-07-11 10:26:13 -07001252 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001253 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001254 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001255
Nick Pelly2eeeec22012-07-18 13:13:37 -07001256 if (!location.isComplete()) {
1257 Log.w(TAG, "Dropping incomplete location: " + location);
1258 return;
1259 }
1260
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001261 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1262 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001263 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001264 mLocationHandler.sendMessageAtFrontOfQueue(m);
1265 }
1266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267
1268 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1269 // Always broadcast the first update
1270 if (lastLoc == null) {
1271 return true;
1272 }
1273
Nick Pellyf1be6862012-05-15 10:53:42 -07001274 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001275 long minTime = record.mRequest.getFastestInterval();
Nick Pelly2eeeec22012-07-18 13:13:37 -07001276 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001277 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 return false;
1279 }
1280
1281 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001282 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 if (minDistance > 0.0) {
1284 if (loc.distanceTo(lastLoc) <= minDistance) {
1285 return false;
1286 }
1287 }
1288
1289 return true;
1290 }
1291
Mike Lockwooda4903f22010-02-17 06:42:23 -05001292 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001293 if (D) Log.d(TAG, "incoming location: " + location);
1294
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001295 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001296 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001298 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001300 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001301 if (p == null) return;
1302
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001303 // Add the coarse location as an extra
1304 Location coarse = mLocationFudger.getOrCreate(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001306 // Update last known locations
1307 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001308 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001309 lastLocation = new Location(provider);
1310 mLastLocation.put(provider, lastLocation);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001311 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001312 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 // Fetch latest status update time
1315 long newStatusUpdateTime = p.getStatusUpdateTime();
1316
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001317 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 Bundle extras = new Bundle();
1319 int status = p.getStatus(extras);
1320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001322 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001325 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001326 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001327 boolean receiverDead = false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001328 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1329 location = lastLocation; // use fine location
1330 } else {
1331 location = coarse; // use coarse location
1332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001334 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001335 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1336 if (lastLoc == null) {
1337 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001338 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001339 } else {
1340 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001342 if (!receiver.callLocationChangedLocked(location)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001343 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001344 receiverDead = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 }
1346 }
1347
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001348 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1350 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1351
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001352 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001354 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001355 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001356 }
1357 }
1358
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001359 // track expired records
1360 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1361 if (deadUpdateRecords == null) {
1362 deadUpdateRecords = new ArrayList<UpdateRecord>();
1363 }
1364 deadUpdateRecords.add(r);
1365 }
1366 // track dead receivers
1367 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001368 if (deadReceivers == null) {
1369 deadReceivers = new ArrayList<Receiver>();
1370 }
1371 if (!deadReceivers.contains(receiver)) {
1372 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 }
1374 }
1375 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001376
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001377 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001379 for (Receiver receiver : deadReceivers) {
1380 removeUpdatesLocked(receiver);
1381 }
1382 }
1383 if (deadUpdateRecords != null) {
1384 for (UpdateRecord r : deadUpdateRecords) {
1385 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 }
1387 }
1388 }
1389
1390 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 @Override
1392 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001393 switch (msg.what) {
1394 case MSG_LOCATION_CHANGED:
1395 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1396 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 }
1398 }
1399 }
1400
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001401 private void handleLocationChanged(Location location, boolean passive) {
1402 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001403
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001404 if (!passive) {
1405 // notify passive provider of the new location
1406 mPassiveProvider.updateLocation(location);
1407 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001409 synchronized (mLock) {
1410 if (isAllowedBySettingsLocked(provider)) {
1411 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001414 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415
Mike Lockwoode97ae402010-09-29 15:23:46 -04001416 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1417 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001418 public void onPackageDisappeared(String packageName, int reason) {
1419 // remove all receivers associated with this package name
1420 synchronized (mLock) {
1421 ArrayList<Receiver> deadReceivers = null;
1422
1423 for (Receiver receiver : mReceivers.values()) {
1424 if (receiver.mPackageName.equals(packageName)) {
1425 if (deadReceivers == null) {
1426 deadReceivers = new ArrayList<Receiver>();
1427 }
1428 deadReceivers.add(receiver);
1429 }
1430 }
1431
1432 // perform removal outside of mReceivers loop
1433 if (deadReceivers != null) {
1434 for (Receiver receiver : deadReceivers) {
1435 removeUpdatesLocked(receiver);
1436 }
1437 }
1438 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001439 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001440 };
1441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 // Wake locks
1443
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001444 private void incrementPendingBroadcasts() {
1445 synchronized (mWakeLock) {
1446 if (mPendingBroadcasts++ == 0) {
1447 try {
1448 mWakeLock.acquire();
1449 log("Acquired wakelock");
1450 } catch (Exception e) {
1451 // This is to catch a runtime exception thrown when we try to release an
1452 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001453 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001454 }
1455 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001456 }
1457 }
1458
1459 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001460 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001461 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001462 try {
1463 // Release wake lock
1464 if (mWakeLock.isHeld()) {
1465 mWakeLock.release();
1466 log("Released wakelock");
1467 } else {
1468 log("Can't release wakelock again!");
1469 }
1470 } catch (Exception e) {
1471 // This is to catch a runtime exception thrown when we try to release an
1472 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001473 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001474 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001475 }
1476 }
1477 }
1478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 // Geocoder
1480
Nick Pellye0fd6932012-07-11 10:26:13 -07001481 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001482 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001483 return mGeocodeProvider != null;
1484 }
1485
Nick Pellye0fd6932012-07-11 10:26:13 -07001486 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001487 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001488 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001489 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001490 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1491 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001493 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 }
1495
Mike Lockwooda55c3212009-04-15 11:10:11 -04001496
Nick Pellye0fd6932012-07-11 10:26:13 -07001497 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001499 double lowerLeftLatitude, double lowerLeftLongitude,
1500 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001501 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001502
1503 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001504 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1505 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1506 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001508 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 }
1510
1511 // Mock Providers
1512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 private void checkMockPermissionsSafe() {
1514 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1515 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1516 if (!allowMocks) {
1517 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1518 }
1519
1520 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1521 PackageManager.PERMISSION_GRANTED) {
1522 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001523 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 }
1525
Nick Pellye0fd6932012-07-11 10:26:13 -07001526 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001527 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 checkMockPermissionsSafe();
1529
Mike Lockwooda4903f22010-02-17 06:42:23 -05001530 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1531 throw new IllegalArgumentException("Cannot mock the passive location provider");
1532 }
1533
Mike Lockwood86328a92009-10-23 08:38:25 -04001534 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001535 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001536 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001537 // remove the real provider if we are replacing GPS or network provider
1538 if (LocationManager.GPS_PROVIDER.equals(name)
1539 || LocationManager.NETWORK_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001540 LocationProviderInterface p = mProvidersByName.get(name);
1541 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001542 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001543 }
1544 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001545 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1547 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001548 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001549 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001550 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 updateProvidersLocked();
1552 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001553 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 }
1555
Nick Pellye0fd6932012-07-11 10:26:13 -07001556 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 public void removeTestProvider(String provider) {
1558 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001559 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001560 MockProvider mockProvider = mMockProviders.get(provider);
1561 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1563 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001564 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001565 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001566 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001567
1568 // reinstate real provider if available
1569 LocationProviderInterface realProvider = mRealProviders.get(provider);
1570 if (realProvider != null) {
1571 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001572 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001573 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001575 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 }
1577 }
1578
Nick Pellye0fd6932012-07-11 10:26:13 -07001579 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 public void setTestProviderLocation(String provider, Location loc) {
1581 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001582 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001583 MockProvider mockProvider = mMockProviders.get(provider);
1584 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1586 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001587 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1588 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001589 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001590 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 }
1592 }
1593
Nick Pellye0fd6932012-07-11 10:26:13 -07001594 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 public void clearTestProviderLocation(String provider) {
1596 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001597 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001598 MockProvider mockProvider = mMockProviders.get(provider);
1599 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1601 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001602 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 }
1604 }
1605
Nick Pellye0fd6932012-07-11 10:26:13 -07001606 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 public void setTestProviderEnabled(String provider, boolean enabled) {
1608 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001609 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001610 MockProvider mockProvider = mMockProviders.get(provider);
1611 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1613 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001614 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001616 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 mEnabledProviders.add(provider);
1618 mDisabledProviders.remove(provider);
1619 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001620 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 mEnabledProviders.remove(provider);
1622 mDisabledProviders.add(provider);
1623 }
1624 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001625 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001626 }
1627 }
1628
Nick Pellye0fd6932012-07-11 10:26:13 -07001629 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 public void clearTestProviderEnabled(String provider) {
1631 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001632 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001633 MockProvider mockProvider = mMockProviders.get(provider);
1634 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1636 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001637 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001638 mEnabledProviders.remove(provider);
1639 mDisabledProviders.remove(provider);
1640 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001641 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 }
1643 }
1644
Nick Pellye0fd6932012-07-11 10:26:13 -07001645 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1647 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001648 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001649 MockProvider mockProvider = mMockProviders.get(provider);
1650 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1652 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001653 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 }
1655 }
1656
Nick Pellye0fd6932012-07-11 10:26:13 -07001657 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 public void clearTestProviderStatus(String provider) {
1659 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001660 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001661 MockProvider mockProvider = mMockProviders.get(provider);
1662 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1664 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001665 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 }
1667 }
1668
1669 private void log(String log) {
1670 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001671 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 }
1673 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001674
1675 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1677 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1678 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001679 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 + Binder.getCallingPid()
1681 + ", uid=" + Binder.getCallingUid());
1682 return;
1683 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001684
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001685 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001688 for (Receiver receiver : mReceivers.values()) {
1689 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001692 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1693 pw.println(" " + entry.getKey() + ":");
1694 for (UpdateRecord record : entry.getValue()) {
1695 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 }
1697 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001699 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1700 String provider = entry.getKey();
1701 Location location = entry.getValue();
1702 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001704
Nick Pellye0fd6932012-07-11 10:26:13 -07001705 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 if (mEnabledProviders.size() > 0) {
1708 pw.println(" Enabled Providers:");
1709 for (String i : mEnabledProviders) {
1710 pw.println(" " + i);
1711 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 }
1714 if (mDisabledProviders.size() > 0) {
1715 pw.println(" Disabled Providers:");
1716 for (String i : mDisabledProviders) {
1717 pw.println(" " + i);
1718 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001719
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 }
1721 if (mMockProviders.size() > 0) {
1722 pw.println(" Mock Providers:");
1723 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001724 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 }
1726 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001727
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001728 pw.append(" fudger: ");
1729 mLocationFudger.dump(fd, pw, args);
1730
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001731 if (args.length > 0 && "short".equals(args[0])) {
1732 return;
1733 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001734 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001735 pw.print(provider.getName() + " Internal State");
1736 if (provider instanceof LocationProviderProxy) {
1737 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1738 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001739 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001740 pw.println(":");
1741 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001742 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 }
1744 }
1745}