blob: 3a45720ba1a0d4d49779eb6f956ac4220aab344f [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 Pelly4035f5a2012-08-17 14:43:49 -070066import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070067import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040068import com.android.server.location.LocationProviderInterface;
69import com.android.server.location.LocationProviderProxy;
70import com.android.server.location.MockProvider;
71import com.android.server.location.PassiveProvider;
72
73import java.io.FileDescriptor;
74import java.io.PrintWriter;
75import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070076import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040077import java.util.HashMap;
78import java.util.HashSet;
79import java.util.List;
80import java.util.Map;
81import java.util.Observable;
82import java.util.Observer;
83import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
85/**
86 * The service class that manages LocationProviders and issues location
87 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -070089public class LocationManagerService extends ILocationManager.Stub implements Observer, Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070091 public static final boolean D = false;
92
93 private static final String WAKELOCK_KEY = TAG;
94 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 private static final String ACCESS_FINE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070097 android.Manifest.permission.ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 private static final String ACCESS_COARSE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070099 android.Manifest.permission.ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700101 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700103 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400104 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700105 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
106
107 private static final String NETWORK_LOCATION_SERVICE_ACTION =
108 "com.android.location.service.v2.NetworkLocationProvider";
109 private static final String FUSED_LOCATION_SERVICE_ACTION =
110 "com.android.location.service.FusedLocationProvider";
111
112 private static final int MSG_LOCATION_CHANGED = 1;
113
Nick Pellyf1be6862012-05-15 10:53:42 -0700114 // Location Providers may sometimes deliver location updates
115 // slightly faster that requested - provide grace period so
116 // we don't unnecessarily filter events that are otherwise on
117 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700118 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700119
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700120 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
121
122 private final Context mContext;
123
124 // used internally for synchronization
125 private final Object mLock = new Object();
126
127 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700128 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700129 private GeofenceManager mGeofenceManager;
130 private PowerManager.WakeLock mWakeLock;
131 private PackageManager mPackageManager;
132 private GeocoderProxy mGeocodeProvider;
133 private IGpsStatusProvider mGpsStatusProvider;
134 private INetInitiatedListener mNetInitiatedListener;
135 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700136 private PassiveProvider mPassiveProvider; // track passive provider for special cases
137 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700138
139 // --- fields below are protected by mWakeLock ---
140 private int mPendingBroadcasts;
141
142 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 // Set of providers that are explicitly enabled
144 private final Set<String> mEnabledProviders = new HashSet<String>();
145
146 // Set of providers that are explicitly disabled
147 private final Set<String> mDisabledProviders = new HashSet<String>();
148
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700149 // Mock (test) providers
150 private final HashMap<String, MockProvider> mMockProviders =
151 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700153 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400154 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700156 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500157 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700158 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400159
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160 // real providers, saved here when mocked out
161 private final HashMap<String, LocationProviderInterface> mRealProviders =
162 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700164 // mapping from provider name to provider
165 private final HashMap<String, LocationProviderInterface> mProvidersByName =
166 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700168 // mapping from provider name to all its UpdateRecords
169 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
170 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700171
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172 // mapping from provider name to last known location
173 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700175 // all providers that operate over proxy, for authorizing incoming location
176 private final ArrayList<LocationProviderProxy> mProxyProviders =
177 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700179 public LocationManagerService(Context context) {
180 super();
181 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800182
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 if (D) Log.d(TAG, "Constructed");
184
185 // most startup is deferred until systemReady()
186 }
187
188 public void systemReady() {
189 Thread thread = new Thread(null, this, THREAD_NAME);
190 thread.start();
191 }
192
193 @Override
194 public void run() {
195 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
196 Looper.prepare();
197 mLocationHandler = new LocationWorkerHandler();
198 init();
199 Looper.loop();
200 }
201
202 private void init() {
203 if (D) Log.d(TAG, "init()");
204
205 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
206 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
207 mPackageManager = mContext.getPackageManager();
208
209 synchronized (mLock) {
210 loadProvidersLocked();
211 }
Nick Pelly4035f5a2012-08-17 14:43:49 -0700212 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
213 mBlacklist.init();
214 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700215 mLocationFudger = new LocationFudger();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700216
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700217 // listen for settings changes
218 ContentResolver resolver = mContext.getContentResolver();
219 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
220 "(" + NameValueTable.NAME + "=?)",
221 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, null);
222 ContentQueryMap query = new ContentQueryMap(settingsCursor, NameValueTable.NAME, true,
223 mLocationHandler);
224 settingsCursor.close();
225 query.addObserver(this);
226 mPackageMonitor.register(mContext, Looper.myLooper(), true);
227 }
228
229 private void loadProvidersLocked() {
230 if (GpsLocationProvider.isSupported()) {
231 // Create a gps location provider
232 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
233 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
234 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
235 addProviderLocked(gpsProvider);
236 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
237 }
238
239 // create a passive location provider, which is always enabled
240 PassiveProvider passiveProvider = new PassiveProvider(this);
241 addProviderLocked(passiveProvider);
242 mEnabledProviders.add(passiveProvider.getName());
243 mPassiveProvider = passiveProvider;
244
245 /*
246 Load package name(s) containing location provider support.
247 These packages can contain services implementing location providers:
248 Geocoder Provider, Network Location Provider, and
249 Fused Location Provider. They will each be searched for
250 service components implementing these providers.
251 The location framework also has support for installation
252 of new location providers at run-time. The new package does not
253 have to be explicitly listed here, however it must have a signature
254 that matches the signature of at least one package on this list.
255 */
256 Resources resources = mContext.getResources();
257 ArrayList<String> providerPackageNames = new ArrayList<String>();
258 String[] pkgs1 = resources.getStringArray(
259 com.android.internal.R.array.config_locationProviderPackageNames);
260 String[] pkgs2 = resources.getStringArray(
261 com.android.internal.R.array.config_overlay_locationProviderPackageNames);
262 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
263 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
264 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
265 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
266
267 // bind to network provider
268 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
269 mContext,
270 LocationManager.NETWORK_PROVIDER,
271 NETWORK_LOCATION_SERVICE_ACTION,
272 providerPackageNames, mLocationHandler);
273 if (networkProvider != null) {
274 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
275 mProxyProviders.add(networkProvider);
276 addProviderLocked(networkProvider);
277 } else {
278 Slog.w(TAG, "no network location provider found");
279 }
280
281 // bind to fused provider
282 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
283 mContext,
284 LocationManager.FUSED_PROVIDER,
285 FUSED_LOCATION_SERVICE_ACTION,
286 providerPackageNames, mLocationHandler);
287 if (fusedLocationProvider != null) {
288 addProviderLocked(fusedLocationProvider);
289 mProxyProviders.add(fusedLocationProvider);
290 mEnabledProviders.add(fusedLocationProvider.getName());
291 } else {
292 Slog.e(TAG, "no fused location provider found",
293 new IllegalStateException("Location service needs a fused location provider"));
294 }
295
296 // bind to geocoder provider
297 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
298 if (mGeocodeProvider == null) {
299 Slog.e(TAG, "no geocoder provider found");
300 }
301
302 updateProvidersLocked();
303 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 /**
306 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
307 * location updates.
308 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700309 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700310 final int mUid; // uid of receiver
311 final int mPid; // pid of receiver
312 final String mPackageName; // package name of receiver
313 final String mPermission; // best permission that receiver has
314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 final ILocationListener mListener;
316 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700318
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400319 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700320
Mike Lockwood48f17512009-04-23 09:12:08 -0700321 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700323 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
324 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700327 if (listener != null) {
328 mKey = listener.asBinder();
329 } else {
330 mKey = intent;
331 }
332 mPermission = checkPermission();
333 mUid = uid;
334 mPid = pid;
335 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 }
337
338 @Override
339 public boolean equals(Object otherObj) {
340 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700341 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 }
343 return false;
344 }
345
346 @Override
347 public int hashCode() {
348 return mKey.hashCode();
349 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 @Override
352 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700353 StringBuilder s = new StringBuilder();
354 s.append("Reciever[");
355 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700357 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700359 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700361 for (String p : mUpdateRecords.keySet()) {
362 s.append(" ").append(mUpdateRecords.get(p).toString());
363 }
364 s.append("]");
365 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 }
367
368 public boolean isListener() {
369 return mListener != null;
370 }
371
372 public boolean isPendingIntent() {
373 return mPendingIntent != null;
374 }
375
376 public ILocationListener getListener() {
377 if (mListener != null) {
378 return mListener;
379 }
380 throw new IllegalStateException("Request for non-existent listener");
381 }
382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
384 if (mListener != null) {
385 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700386 synchronized (this) {
387 // synchronize to ensure incrementPendingBroadcastsLocked()
388 // is called before decrementPendingBroadcasts()
389 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700390 // call this after broadcasting so we do not increment
391 // if we throw an exeption.
392 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 } catch (RemoteException e) {
395 return false;
396 }
397 } else {
398 Intent statusChanged = new Intent();
399 statusChanged.putExtras(extras);
400 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
401 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700402 synchronized (this) {
403 // synchronize to ensure incrementPendingBroadcastsLocked()
404 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700405 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700406 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700407 // call this after broadcasting so we do not increment
408 // if we throw an exeption.
409 incrementPendingBroadcastsLocked();
410 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 } catch (PendingIntent.CanceledException e) {
412 return false;
413 }
414 }
415 return true;
416 }
417
418 public boolean callLocationChangedLocked(Location location) {
419 if (mListener != null) {
420 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700421 synchronized (this) {
422 // synchronize to ensure incrementPendingBroadcastsLocked()
423 // is called before decrementPendingBroadcasts()
424 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700425 // call this after broadcasting so we do not increment
426 // if we throw an exeption.
427 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 } catch (RemoteException e) {
430 return false;
431 }
432 } else {
433 Intent locationChanged = new Intent();
434 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
435 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700436 synchronized (this) {
437 // synchronize to ensure incrementPendingBroadcastsLocked()
438 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700439 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700440 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700441 // call this after broadcasting so we do not increment
442 // if we throw an exeption.
443 incrementPendingBroadcastsLocked();
444 }
445 } catch (PendingIntent.CanceledException e) {
446 return false;
447 }
448 }
449 return true;
450 }
451
452 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
453 if (mListener != null) {
454 try {
455 synchronized (this) {
456 // synchronize to ensure incrementPendingBroadcastsLocked()
457 // is called before decrementPendingBroadcasts()
458 if (enabled) {
459 mListener.onProviderEnabled(provider);
460 } else {
461 mListener.onProviderDisabled(provider);
462 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700463 // call this after broadcasting so we do not increment
464 // if we throw an exeption.
465 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700466 }
467 } catch (RemoteException e) {
468 return false;
469 }
470 } else {
471 Intent providerIntent = new Intent();
472 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
473 try {
474 synchronized (this) {
475 // synchronize to ensure incrementPendingBroadcastsLocked()
476 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700477 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700478 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700479 // call this after broadcasting so we do not increment
480 // if we throw an exeption.
481 incrementPendingBroadcastsLocked();
482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 } catch (PendingIntent.CanceledException e) {
484 return false;
485 }
486 }
487 return true;
488 }
489
Nick Pellyf1be6862012-05-15 10:53:42 -0700490 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700492 if (D) Log.d(TAG, "Location listener died");
493
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400494 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 removeUpdatesLocked(this);
496 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700497 synchronized (this) {
498 if (mPendingBroadcasts > 0) {
499 LocationManagerService.this.decrementPendingBroadcasts();
500 mPendingBroadcasts = 0;
501 }
502 }
503 }
504
Nick Pellye0fd6932012-07-11 10:26:13 -0700505 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700506 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
507 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400508 synchronized (this) {
509 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700510 }
511 }
512
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400513 // this must be called while synchronized by caller in a synchronized block
514 // containing the sending of the broadcaset
515 private void incrementPendingBroadcastsLocked() {
516 if (mPendingBroadcasts++ == 0) {
517 LocationManagerService.this.incrementPendingBroadcasts();
518 }
519 }
520
521 private void decrementPendingBroadcastsLocked() {
522 if (--mPendingBroadcasts == 0) {
523 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700524 }
525 }
526 }
527
Nick Pellye0fd6932012-07-11 10:26:13 -0700528 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700529 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400530 //Do not use getReceiver here as that will add the ILocationListener to
531 //the receiver list if it is not found. If it is not found then the
532 //LocationListener was removed when it had a pending broadcast and should
533 //not be added back.
534 IBinder binder = listener.asBinder();
535 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700536 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400537 synchronized (receiver) {
538 // so wakelock calls will succeed
539 long identity = Binder.clearCallingIdentity();
540 receiver.decrementPendingBroadcastsLocked();
541 Binder.restoreCallingIdentity(identity);
542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 }
544 }
545
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700546 /** Settings Observer callback */
547 @Override
548 public void update(Observable o, Object arg) {
549 synchronized (mLock) {
550 updateProvidersLocked();
Mike Lockwood9637d472009-04-02 21:41:57 -0700551 }
552 }
553
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700554 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400555 mProviders.add(provider);
556 mProvidersByName.put(provider.getName(), provider);
557 }
558
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700559 private void removeProviderLocked(LocationProviderInterface provider) {
560 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400561 mProviders.remove(provider);
562 mProvidersByName.remove(provider.getName());
563 }
564
Mike Lockwood3d12b512009-04-21 23:25:35 -0700565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 private boolean isAllowedBySettingsLocked(String provider) {
567 if (mEnabledProviders.contains(provider)) {
568 return true;
569 }
570 if (mDisabledProviders.contains(provider)) {
571 return false;
572 }
573 // Use system settings
574 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575
Brad Larson8eb3ea62009-12-29 11:47:55 -0600576 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
578
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700579 /**
580 * Throw SecurityException if caller has neither COARSE or FINE.
581 * Otherwise, return the best permission.
582 */
583 private String checkPermission() {
584 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
585 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700586 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700587 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
588 PackageManager.PERMISSION_GRANTED) {
589 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700591
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700592 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
593 "ACCESS_FINE_LOCATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 }
595
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700596 /**
597 * Returns all providers by name, including passive, but excluding
598 * fused.
599 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700600 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700602 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700604 ArrayList<String> out;
605 synchronized (mLock) {
606 out = new ArrayList<String>(mProviders.size());
607 for (LocationProviderInterface provider : mProviders) {
608 String name = provider.getName();
609 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700610 continue;
611 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 out.add(name);
613 }
614 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700615
616 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 return out;
618 }
619
Mike Lockwood03ca2162010-04-01 08:10:09 -0700620 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700621 * Return all providers by name, that match criteria and are optionally
622 * enabled.
623 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700624 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700625 @Override
626 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
627 checkPermission();
Mike Lockwood03ca2162010-04-01 08:10:09 -0700628
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700629 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700630 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700631 out = new ArrayList<String>(mProviders.size());
632 for (LocationProviderInterface provider : mProviders) {
633 String name = provider.getName();
634 if (LocationManager.FUSED_PROVIDER.equals(name)) {
635 continue;
636 }
637 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
638 continue;
639 }
640 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
641 name, provider.getProperties(), criteria)) {
642 continue;
643 }
644 out.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700645 }
646 }
647
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700648 if (D) Log.d(TAG, "getProviders()=" + out);
649 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700650 }
651
652 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700653 * Return the name of the best provider given a Criteria object.
654 * This method has been deprecated from the public API,
655 * and the whole LoactionProvider (including #meetsCriteria)
656 * has been deprecated as well. So this method now uses
657 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700658 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700659 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700660 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 String result = null;
662 checkPermission();
663
664 List<String> providers = getProviders(criteria, enabledOnly);
665 if (providers.size() < 1) {
666 result = pickBest(providers);
667 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
668 return result;
669 }
670 providers = getProviders(null, enabledOnly);
671 if (providers.size() >= 1) {
672 result = pickBest(providers);
673 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
674 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700675 }
676
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700677 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700678 return null;
679 }
680
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700681 private String pickBest(List<String> providers) {
682 if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
683 return LocationManager.NETWORK_PROVIDER;
684 } else if (providers.contains(LocationManager.GPS_PROVIDER)) {
685 return LocationManager.GPS_PROVIDER;
686 } else {
687 return providers.get(0);
688 }
689 }
690
Nick Pellye0fd6932012-07-11 10:26:13 -0700691 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700692 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700693 checkPermission();
694
Mike Lockwood03ca2162010-04-01 08:10:09 -0700695 LocationProviderInterface p = mProvidersByName.get(provider);
696 if (p == null) {
697 throw new IllegalArgumentException("provider=" + provider);
698 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700699
700 boolean result = LocationProvider.propertiesMeetCriteria(
701 p.getName(), p.getProperties(), criteria);
702 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
703 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700704 }
705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700707 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400708 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500709 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 boolean isEnabled = p.isEnabled();
711 String name = p.getName();
712 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 if (isEnabled && !shouldBeEnabled) {
714 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700715 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 } else if (!isEnabled && shouldBeEnabled) {
717 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700718 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700720 }
721 if (changesMade) {
722 mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 }
724 }
725
726 private void updateProviderListenersLocked(String provider, boolean enabled) {
727 int listeners = 0;
728
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500729 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700730 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731
732 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
735 if (records != null) {
736 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700737 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 UpdateRecord record = records.get(i);
739 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700740 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
741 if (deadReceivers == null) {
742 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 }
Simon Schoar46866572009-06-10 21:12:10 +0200744 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 }
746 listeners++;
747 }
748 }
749
750 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700751 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 removeUpdatesLocked(deadReceivers.get(i));
753 }
754 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 if (enabled) {
757 p.enable();
758 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700759 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 }
761 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 }
765
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700766 private void applyRequirementsLocked(String provider) {
767 LocationProviderInterface p = mProvidersByName.get(provider);
768 if (p == null) return;
769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700771 WorkSource worksource = new WorkSource();
772 ProviderRequest providerRequest = new ProviderRequest();
773
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700775 for (UpdateRecord record : records) {
776 LocationRequest locationRequest = record.mRequest;
777
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700778 providerRequest.locationRequests.add(locationRequest);
779 if (locationRequest.getInterval() < providerRequest.interval) {
780 providerRequest.reportLocation = true;
781 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700782 }
783 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700784
785 if (providerRequest.reportLocation) {
786 // calculate who to blame for power
787 // This is somewhat arbitrary. We pick a threshold interval
788 // that is slightly higher that the minimum interval, and
789 // spread the blame across all applications with a request
790 // under that threshold.
791 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
792 for (UpdateRecord record : records) {
793 LocationRequest locationRequest = record.mRequest;
794 if (locationRequest.getInterval() <= thresholdInterval) {
795 worksource.add(record.mReceiver.mUid);
796 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700797 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 }
799 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700800
801 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
802 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 }
804
805 private class UpdateRecord {
806 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700807 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400809 Location mLastFixBroadcast;
810 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811
812 /**
813 * Note: must be constructed with lock held.
814 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700815 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700817 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819
820 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
821 if (records == null) {
822 records = new ArrayList<UpdateRecord>();
823 mRecordsByProvider.put(provider, records);
824 }
825 if (!records.contains(this)) {
826 records.add(this);
827 }
828 }
829
830 /**
831 * Method to be called when a record will no longer be used. Calling this multiple times
832 * must have the same effect as calling it once.
833 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700834 void disposeLocked(boolean removeReceiver) {
835 // remove from mRecordsByProvider
836 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
837 if (globalRecords != null) {
838 globalRecords.remove(this);
839 }
840
841 if (!removeReceiver) return; // the caller will handle the rest
842
843 // remove from Receiver#mUpdateRecords
844 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
845 if (receiverRecords != null) {
846 receiverRecords.remove(this.mProvider);
847
848 // and also remove the Receiver if it has no more update records
849 if (removeReceiver && receiverRecords.size() == 0) {
850 removeUpdatesLocked(mReceiver);
851 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854
855 @Override
856 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700857 StringBuilder s = new StringBuilder();
858 s.append("UpdateRecord[");
859 s.append(mProvider);
860 s.append(' ').append(mReceiver.mPackageName).append('(');
861 s.append(mReceiver.mUid).append(')');
862 s.append(' ').append(mRequest);
863 s.append(']');
864 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 }
867
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700868 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400869 IBinder binder = listener.asBinder();
870 Receiver receiver = mReceivers.get(binder);
871 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700872 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400873 mReceivers.put(binder, receiver);
874
875 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700876 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400877 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800878 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400879 return null;
880 }
881 }
882 return receiver;
883 }
884
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700885 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400886 Receiver receiver = mReceivers.get(intent);
887 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700888 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400889 mReceivers.put(intent, receiver);
890 }
891 return receiver;
892 }
893
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700894 private String checkPermissionAndRequest(LocationRequest request) {
895 String perm = checkPermission();
896
897 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700898 switch (request.getQuality()) {
899 case LocationRequest.ACCURACY_FINE:
900 request.setQuality(LocationRequest.ACCURACY_BLOCK);
901 break;
902 case LocationRequest.POWER_HIGH:
903 request.setQuality(LocationRequest.POWER_LOW);
904 break;
905 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700906 // throttle
907 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
908 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
909 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700910 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
911 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
912 }
913 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700914 // make getFastestInterval() the minimum of interval and fastest interval
915 if (request.getFastestInterval() > request.getInterval()) {
916 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400917 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700918 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400919 }
920
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700921 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700922 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700923 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700924 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700925 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700926 String[] packages = mPackageManager.getPackagesForUid(uid);
927 if (packages == null) {
928 throw new SecurityException("invalid UID " + uid);
929 }
930 for (String pkg : packages) {
931 if (packageName.equals(pkg)) return;
932 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700933 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700934 }
935
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700936 private void checkPendingIntent(PendingIntent intent) {
937 if (intent == null) {
938 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700939 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700940 }
941
942 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
943 int pid, int uid, String packageName) {
944 if (intent == null && listener == null) {
945 throw new IllegalArgumentException("need eiter listener or intent");
946 } else if (intent != null && listener != null) {
947 throw new IllegalArgumentException("cannot register both listener and intent");
948 } else if (intent != null) {
949 checkPendingIntent(intent);
950 return getReceiver(intent, pid, uid, packageName);
951 } else {
952 return getReceiver(listener, pid, uid, packageName);
953 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700954 }
955
Nick Pellye0fd6932012-07-11 10:26:13 -0700956 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700957 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
958 PendingIntent intent, String packageName) {
959 if (request == null) request = DEFAULT_LOCATION_REQUEST;
960 checkPackageName(packageName);
961 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700963 final int pid = Binder.getCallingPid();
964 final int uid = Binder.getCallingUid();
965 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966
Nick Pelly2b7a0d02012-08-17 15:09:44 -0700967 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 long identity = Binder.clearCallingIdentity();
969 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700970 synchronized (mLock) {
971 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400972 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 } finally {
974 Binder.restoreCallingIdentity(identity);
975 }
976 }
977
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700978 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
979 int pid, int uid, String packageName) {
980 // Figure out the provider. Either its explicitly request (legacy use cases), or
981 // use the fused provider
982 if (request == null) request = DEFAULT_LOCATION_REQUEST;
983 String name = request.getProvider();
984 if (name == null) name = LocationManager.FUSED_PROVIDER;
985 LocationProviderInterface provider = mProvidersByName.get(name);
986 if (provider == null) {
987 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
988 }
989
990 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
991 name + " " + request + " from " + packageName + "(" + uid + ")");
992
993 UpdateRecord record = new UpdateRecord(name, request, receiver);
994 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
995 if (oldRecord != null) {
996 oldRecord.disposeLocked(false);
997 }
998
999 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1000 if (isProviderEnabled) {
1001 applyRequirementsLocked(name);
1002 } else {
1003 // Notify the listener that updates are currently disabled
1004 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 }
1006 }
1007
Nick Pellye0fd6932012-07-11 10:26:13 -07001008 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001009 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1010 String packageName) {
1011 checkPackageName(packageName);
1012 checkPermission();
1013 final int pid = Binder.getCallingPid();
1014 final int uid = Binder.getCallingUid();
1015 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1016
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001017 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001018 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001020 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001021 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001023 } finally {
1024 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 }
1026 }
1027
1028 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001029 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1030
1031 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1032 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1033 synchronized (receiver) {
1034 if (receiver.mPendingBroadcasts > 0) {
1035 decrementPendingBroadcasts();
1036 receiver.mPendingBroadcasts = 0;
1037 }
1038 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 }
1040
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001041 // Record which providers were associated with this listener
1042 HashSet<String> providers = new HashSet<String>();
1043 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1044 if (oldRecords != null) {
1045 // Call dispose() on the obsolete update records.
1046 for (UpdateRecord record : oldRecords.values()) {
1047 record.disposeLocked(false);
1048 }
1049 // Accumulate providers
1050 providers.addAll(oldRecords.keySet());
1051 }
1052
1053 // update provider
1054 for (String provider : providers) {
1055 // If provider is already disabled, don't need to do anything
1056 if (!isAllowedBySettingsLocked(provider)) {
1057 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001058 }
1059
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001060 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 }
1062 }
1063
Nick Pellye0fd6932012-07-11 10:26:13 -07001064 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001065 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001066 if (D) Log.d(TAG, "getLastLocation: " + request);
1067 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1068 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001069 checkPackageName(packageName);
1070
1071 if (mBlacklist.isBlacklisted(packageName)) {
1072 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1073 packageName);
1074 return null;
1075 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001076
1077 synchronized (mLock) {
1078 // Figure out the provider. Either its explicitly request (deprecated API's),
1079 // or use the fused provider
1080 String name = request.getProvider();
1081 if (name == null) name = LocationManager.FUSED_PROVIDER;
1082 LocationProviderInterface provider = mProvidersByName.get(name);
1083 if (provider == null) return null;
1084
1085 if (!isAllowedBySettingsLocked(name)) return null;
1086
1087 Location location = mLastLocation.get(name);
1088 if (ACCESS_FINE_LOCATION.equals(perm)) {
1089 return location;
1090 } else {
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001091 return mLocationFudger.getOrCreate(location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001092 }
1093 }
1094 }
1095
1096 @Override
1097 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1098 String packageName) {
1099 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1100 checkPermissionAndRequest(request);
1101 checkPendingIntent(intent);
1102 checkPackageName(packageName);
1103
1104 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1105
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001106 // geo-fence manager uses the public location API, need to clear identity
1107 int uid = Binder.getCallingUid();
1108 long identity = Binder.clearCallingIdentity();
1109 try {
1110 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1111 } finally {
1112 Binder.restoreCallingIdentity(identity);
1113 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001114 }
1115
1116 @Override
1117 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1118 checkPermission();
1119 checkPendingIntent(intent);
1120 checkPackageName(packageName);
1121
1122 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1123
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001124 // geo-fence manager uses the public location API, need to clear identity
1125 long identity = Binder.clearCallingIdentity();
1126 try {
1127 mGeofenceManager.removeFence(geofence, intent);
1128 } finally {
1129 Binder.restoreCallingIdentity(identity);
1130 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001131 }
1132
1133
1134 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001136 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 return false;
1138 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001139 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 PackageManager.PERMISSION_GRANTED) {
1141 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1142 }
1143
1144 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001145 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001147 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 return false;
1149 }
1150 return true;
1151 }
1152
Nick Pellye0fd6932012-07-11 10:26:13 -07001153 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001155 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001156 try {
1157 mGpsStatusProvider.removeGpsStatusListener(listener);
1158 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001159 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 }
1162 }
1163
Nick Pellye0fd6932012-07-11 10:26:13 -07001164 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001166 if (provider == null) {
1167 // throw NullPointerException to remain compatible with previous implementation
1168 throw new NullPointerException();
1169 }
1170
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001171 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001173 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 != PackageManager.PERMISSION_GRANTED)) {
1175 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1176 }
1177
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001178 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001179 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001180 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001181
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001182 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 }
1184 }
1185
Nick Pellye0fd6932012-07-11 10:26:13 -07001186 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001187 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001188 if (Binder.getCallingUid() != Process.myUid()) {
1189 throw new SecurityException(
1190 "calling sendNiResponse from outside of the system is not allowed");
1191 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001192 try {
1193 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001194 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001195 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001196 return false;
1197 }
1198 }
1199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001201 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001202 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 * accessed by the caller
1204 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001205 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001206 public ProviderProperties getProviderProperties(String provider) {
1207 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001209 LocationProviderInterface p;
1210 synchronized (mLock) {
1211 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 }
1213
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001214 if (p == null) return null;
1215 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 }
1217
Nick Pellye0fd6932012-07-11 10:26:13 -07001218 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001220 checkPermission();
1221 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1222
1223 synchronized (mLock) {
1224 LocationProviderInterface p = mProvidersByName.get(provider);
1225 if (p == null) return false;
1226
1227 return isAllowedBySettingsLocked(provider);
1228 }
1229 }
1230
1231 private void checkCallerIsProvider() {
1232 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1233 == PackageManager.PERMISSION_GRANTED) {
1234 return;
1235 }
1236
1237 // Previously we only used the INSTALL_LOCATION_PROVIDER
1238 // check. But that is system or signature
1239 // protection level which is not flexible enough for
1240 // providers installed oustide the system image. So
1241 // also allow providers with a UID matching the
1242 // currently bound package name
1243
1244 int uid = Binder.getCallingUid();
1245
1246 if (mGeocodeProvider != null) {
1247 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1248 }
1249 for (LocationProviderProxy proxy : mProxyProviders) {
1250 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1251 }
1252 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1253 "or UID of a currently bound location provider");
1254 }
1255
1256 private boolean doesPackageHaveUid(int uid, String packageName) {
1257 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 return false;
1259 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001260 try {
1261 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1262 if (appInfo.uid != uid) {
1263 return false;
1264 }
1265 } catch (NameNotFoundException e) {
1266 return false;
1267 }
1268 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 }
1270
Nick Pellye0fd6932012-07-11 10:26:13 -07001271 @Override
Mike Lockwooda4903f252010-02-17 06:42:23 -05001272 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001273 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001274
Nick Pelly2eeeec22012-07-18 13:13:37 -07001275 if (!location.isComplete()) {
1276 Log.w(TAG, "Dropping incomplete location: " + location);
1277 return;
1278 }
1279
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001280 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1281 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f252010-02-17 06:42:23 -05001282 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001283 mLocationHandler.sendMessageAtFrontOfQueue(m);
1284 }
1285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286
1287 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1288 // Always broadcast the first update
1289 if (lastLoc == null) {
1290 return true;
1291 }
1292
Nick Pellyf1be6862012-05-15 10:53:42 -07001293 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001294 long minTime = record.mRequest.getFastestInterval();
Nick Pelly2eeeec22012-07-18 13:13:37 -07001295 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001296 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 return false;
1298 }
1299
1300 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001301 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 if (minDistance > 0.0) {
1303 if (loc.distanceTo(lastLoc) <= minDistance) {
1304 return false;
1305 }
1306 }
1307
1308 return true;
1309 }
1310
Mike Lockwooda4903f252010-02-17 06:42:23 -05001311 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001312 if (D) Log.d(TAG, "incoming location: " + location);
1313
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001314 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f252010-02-17 06:42:23 -05001315 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001317 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001319 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001320 if (p == null) return;
1321
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001322 // Add the coarse location as an extra
1323 Location coarse = mLocationFudger.getOrCreate(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001325 // Update last known locations
1326 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001327 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001328 lastLocation = new Location(provider);
1329 mLastLocation.put(provider, lastLocation);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001330 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001331 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 // Fetch latest status update time
1334 long newStatusUpdateTime = p.getStatusUpdateTime();
1335
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001336 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 Bundle extras = new Bundle();
1338 int status = p.getStatus(extras);
1339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001341 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001344 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001346 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001347
1348 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1349 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1350 receiver.mPackageName);
1351 continue;
1352 }
1353
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001354 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1355 location = lastLocation; // use fine location
1356 } else {
1357 location = coarse; // use coarse location
1358 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001360 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001361 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1362 if (lastLoc == null) {
1363 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001364 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001365 } else {
1366 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001368 if (!receiver.callLocationChangedLocked(location)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001369 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001370 receiverDead = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 }
1372 }
1373
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001374 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1376 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1377
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001378 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001380 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001381 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001382 }
1383 }
1384
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001385 // track expired records
1386 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1387 if (deadUpdateRecords == null) {
1388 deadUpdateRecords = new ArrayList<UpdateRecord>();
1389 }
1390 deadUpdateRecords.add(r);
1391 }
1392 // track dead receivers
1393 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001394 if (deadReceivers == null) {
1395 deadReceivers = new ArrayList<Receiver>();
1396 }
1397 if (!deadReceivers.contains(receiver)) {
1398 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 }
1400 }
1401 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001402
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001403 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001405 for (Receiver receiver : deadReceivers) {
1406 removeUpdatesLocked(receiver);
1407 }
1408 }
1409 if (deadUpdateRecords != null) {
1410 for (UpdateRecord r : deadUpdateRecords) {
1411 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 }
1413 }
1414 }
1415
1416 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 @Override
1418 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001419 switch (msg.what) {
1420 case MSG_LOCATION_CHANGED:
1421 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1422 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 }
1424 }
1425 }
1426
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001427 private void handleLocationChanged(Location location, boolean passive) {
1428 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001429
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001430 if (!passive) {
1431 // notify passive provider of the new location
1432 mPassiveProvider.updateLocation(location);
1433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001435 synchronized (mLock) {
1436 if (isAllowedBySettingsLocked(provider)) {
1437 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441
Mike Lockwoode97ae402010-09-29 15:23:46 -04001442 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1443 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001444 public void onPackageDisappeared(String packageName, int reason) {
1445 // remove all receivers associated with this package name
1446 synchronized (mLock) {
1447 ArrayList<Receiver> deadReceivers = null;
1448
1449 for (Receiver receiver : mReceivers.values()) {
1450 if (receiver.mPackageName.equals(packageName)) {
1451 if (deadReceivers == null) {
1452 deadReceivers = new ArrayList<Receiver>();
1453 }
1454 deadReceivers.add(receiver);
1455 }
1456 }
1457
1458 // perform removal outside of mReceivers loop
1459 if (deadReceivers != null) {
1460 for (Receiver receiver : deadReceivers) {
1461 removeUpdatesLocked(receiver);
1462 }
1463 }
1464 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001465 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001466 };
1467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 // Wake locks
1469
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001470 private void incrementPendingBroadcasts() {
1471 synchronized (mWakeLock) {
1472 if (mPendingBroadcasts++ == 0) {
1473 try {
1474 mWakeLock.acquire();
1475 log("Acquired wakelock");
1476 } catch (Exception e) {
1477 // This is to catch a runtime exception thrown when we try to release an
1478 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001479 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001480 }
1481 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001482 }
1483 }
1484
1485 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001486 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001487 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001488 try {
1489 // Release wake lock
1490 if (mWakeLock.isHeld()) {
1491 mWakeLock.release();
1492 log("Released wakelock");
1493 } else {
1494 log("Can't release wakelock again!");
1495 }
1496 } catch (Exception e) {
1497 // This is to catch a runtime exception thrown when we try to release an
1498 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001499 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001500 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001501 }
1502 }
1503 }
1504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505 // Geocoder
1506
Nick Pellye0fd6932012-07-11 10:26:13 -07001507 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001508 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001509 return mGeocodeProvider != null;
1510 }
1511
Nick Pellye0fd6932012-07-11 10:26:13 -07001512 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001514 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001515 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001516 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1517 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001519 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 }
1521
Mike Lockwooda55c3212009-04-15 11:10:11 -04001522
Nick Pellye0fd6932012-07-11 10:26:13 -07001523 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001525 double lowerLeftLatitude, double lowerLeftLongitude,
1526 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001527 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001528
1529 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001530 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1531 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1532 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001534 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 }
1536
1537 // Mock Providers
1538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 private void checkMockPermissionsSafe() {
1540 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1541 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1542 if (!allowMocks) {
1543 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1544 }
1545
1546 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1547 PackageManager.PERMISSION_GRANTED) {
1548 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 }
1551
Nick Pellye0fd6932012-07-11 10:26:13 -07001552 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001553 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 checkMockPermissionsSafe();
1555
Mike Lockwooda4903f252010-02-17 06:42:23 -05001556 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1557 throw new IllegalArgumentException("Cannot mock the passive location provider");
1558 }
1559
Mike Lockwood86328a92009-10-23 08:38:25 -04001560 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001561 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001562 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001563 // remove the real provider if we are replacing GPS or network provider
1564 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001565 || LocationManager.NETWORK_PROVIDER.equals(name)
1566 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001567 LocationProviderInterface p = mProvidersByName.get(name);
1568 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001569 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001570 }
1571 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001572 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1574 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001575 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001576 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001577 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 updateProvidersLocked();
1579 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001580 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 }
1582
Nick Pellye0fd6932012-07-11 10:26:13 -07001583 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 public void removeTestProvider(String provider) {
1585 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001586 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001587 MockProvider mockProvider = mMockProviders.get(provider);
1588 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001589 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1590 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001591 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001592 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001593 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001594
1595 // reinstate real provider if available
1596 LocationProviderInterface realProvider = mRealProviders.get(provider);
1597 if (realProvider != null) {
1598 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001599 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001600 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001602 Binder.restoreCallingIdentity(identity);
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 setTestProviderLocation(String provider, Location loc) {
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 Lockwood95427cd2009-05-07 13:27:54 -04001614 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1615 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001616 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001617 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001618 }
1619 }
1620
Nick Pellye0fd6932012-07-11 10:26:13 -07001621 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 public void clearTestProviderLocation(String provider) {
1623 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001624 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001625 MockProvider mockProvider = mMockProviders.get(provider);
1626 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1628 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001629 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 }
1631 }
1632
Nick Pellye0fd6932012-07-11 10:26:13 -07001633 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 public void setTestProviderEnabled(String provider, boolean enabled) {
1635 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001636 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001637 MockProvider mockProvider = mMockProviders.get(provider);
1638 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1640 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001641 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001643 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 mEnabledProviders.add(provider);
1645 mDisabledProviders.remove(provider);
1646 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001647 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 mEnabledProviders.remove(provider);
1649 mDisabledProviders.add(provider);
1650 }
1651 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001652 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 }
1654 }
1655
Nick Pellye0fd6932012-07-11 10:26:13 -07001656 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001657 public void clearTestProviderEnabled(String provider) {
1658 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001659 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001660 MockProvider mockProvider = mMockProviders.get(provider);
1661 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1663 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001664 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 mEnabledProviders.remove(provider);
1666 mDisabledProviders.remove(provider);
1667 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001668 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 }
1670 }
1671
Nick Pellye0fd6932012-07-11 10:26:13 -07001672 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1674 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001675 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001676 MockProvider mockProvider = mMockProviders.get(provider);
1677 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1679 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001680 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 }
1682 }
1683
Nick Pellye0fd6932012-07-11 10:26:13 -07001684 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 public void clearTestProviderStatus(String provider) {
1686 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001687 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001688 MockProvider mockProvider = mMockProviders.get(provider);
1689 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1691 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001692 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 }
1694 }
1695
1696 private void log(String log) {
1697 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001698 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
1700 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001701
1702 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1704 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1705 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001706 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 + Binder.getCallingPid()
1708 + ", uid=" + Binder.getCallingUid());
1709 return;
1710 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001711
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001712 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001715 for (Receiver receiver : mReceivers.values()) {
1716 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001719 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1720 pw.println(" " + entry.getKey() + ":");
1721 for (UpdateRecord record : entry.getValue()) {
1722 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 }
1724 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001726 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1727 String provider = entry.getKey();
1728 Location location = entry.getValue();
1729 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001731
Nick Pellye0fd6932012-07-11 10:26:13 -07001732 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 if (mEnabledProviders.size() > 0) {
1735 pw.println(" Enabled Providers:");
1736 for (String i : mEnabledProviders) {
1737 pw.println(" " + i);
1738 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740 }
1741 if (mDisabledProviders.size() > 0) {
1742 pw.println(" Disabled Providers:");
1743 for (String i : mDisabledProviders) {
1744 pw.println(" " + i);
1745 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001747 pw.append(" ");
1748 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001749 if (mMockProviders.size() > 0) {
1750 pw.println(" Mock Providers:");
1751 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001752 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 }
1754 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001755
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001756 pw.append(" fudger: ");
1757 mLocationFudger.dump(fd, pw, args);
1758
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001759 if (args.length > 0 && "short".equals(args[0])) {
1760 return;
1761 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001762 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001763 pw.print(provider.getName() + " Internal State");
1764 if (provider instanceof LocationProviderProxy) {
1765 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1766 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001767 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001768 pw.println(":");
1769 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001770 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 }
1772 }
1773}