blob: 8a564f7104e973d629d5a43731854d196f44ed07 [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
217 // Register for Network (Wifi or Mobile) updates
218 IntentFilter filter = new IntentFilter();
219 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
220
221 // listen for settings changes
222 ContentResolver resolver = mContext.getContentResolver();
223 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
224 "(" + NameValueTable.NAME + "=?)",
225 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, null);
226 ContentQueryMap query = new ContentQueryMap(settingsCursor, NameValueTable.NAME, true,
227 mLocationHandler);
228 settingsCursor.close();
229 query.addObserver(this);
230 mPackageMonitor.register(mContext, Looper.myLooper(), true);
231 }
232
233 private void loadProvidersLocked() {
234 if (GpsLocationProvider.isSupported()) {
235 // Create a gps location provider
236 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
237 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
238 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
239 addProviderLocked(gpsProvider);
240 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
241 }
242
243 // create a passive location provider, which is always enabled
244 PassiveProvider passiveProvider = new PassiveProvider(this);
245 addProviderLocked(passiveProvider);
246 mEnabledProviders.add(passiveProvider.getName());
247 mPassiveProvider = passiveProvider;
248
249 /*
250 Load package name(s) containing location provider support.
251 These packages can contain services implementing location providers:
252 Geocoder Provider, Network Location Provider, and
253 Fused Location Provider. They will each be searched for
254 service components implementing these providers.
255 The location framework also has support for installation
256 of new location providers at run-time. The new package does not
257 have to be explicitly listed here, however it must have a signature
258 that matches the signature of at least one package on this list.
259 */
260 Resources resources = mContext.getResources();
261 ArrayList<String> providerPackageNames = new ArrayList<String>();
262 String[] pkgs1 = resources.getStringArray(
263 com.android.internal.R.array.config_locationProviderPackageNames);
264 String[] pkgs2 = resources.getStringArray(
265 com.android.internal.R.array.config_overlay_locationProviderPackageNames);
266 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
267 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
268 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
269 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
270
271 // bind to network provider
272 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
273 mContext,
274 LocationManager.NETWORK_PROVIDER,
275 NETWORK_LOCATION_SERVICE_ACTION,
276 providerPackageNames, mLocationHandler);
277 if (networkProvider != null) {
278 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
279 mProxyProviders.add(networkProvider);
280 addProviderLocked(networkProvider);
281 } else {
282 Slog.w(TAG, "no network location provider found");
283 }
284
285 // bind to fused provider
286 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
287 mContext,
288 LocationManager.FUSED_PROVIDER,
289 FUSED_LOCATION_SERVICE_ACTION,
290 providerPackageNames, mLocationHandler);
291 if (fusedLocationProvider != null) {
292 addProviderLocked(fusedLocationProvider);
293 mProxyProviders.add(fusedLocationProvider);
294 mEnabledProviders.add(fusedLocationProvider.getName());
295 } else {
296 Slog.e(TAG, "no fused location provider found",
297 new IllegalStateException("Location service needs a fused location provider"));
298 }
299
300 // bind to geocoder provider
301 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
302 if (mGeocodeProvider == null) {
303 Slog.e(TAG, "no geocoder provider found");
304 }
305
306 updateProvidersLocked();
307 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 /**
310 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
311 * location updates.
312 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700313 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700314 final int mUid; // uid of receiver
315 final int mPid; // pid of receiver
316 final String mPackageName; // package name of receiver
317 final String mPermission; // best permission that receiver has
318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 final ILocationListener mListener;
320 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700322
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400323 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700324
Mike Lockwood48f17512009-04-23 09:12:08 -0700325 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700327 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
328 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700331 if (listener != null) {
332 mKey = listener.asBinder();
333 } else {
334 mKey = intent;
335 }
336 mPermission = checkPermission();
337 mUid = uid;
338 mPid = pid;
339 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 }
341
342 @Override
343 public boolean equals(Object otherObj) {
344 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700345 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 }
347 return false;
348 }
349
350 @Override
351 public int hashCode() {
352 return mKey.hashCode();
353 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 @Override
356 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700357 StringBuilder s = new StringBuilder();
358 s.append("Reciever[");
359 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700361 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700363 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700365 for (String p : mUpdateRecords.keySet()) {
366 s.append(" ").append(mUpdateRecords.get(p).toString());
367 }
368 s.append("]");
369 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 }
371
372 public boolean isListener() {
373 return mListener != null;
374 }
375
376 public boolean isPendingIntent() {
377 return mPendingIntent != null;
378 }
379
380 public ILocationListener getListener() {
381 if (mListener != null) {
382 return mListener;
383 }
384 throw new IllegalStateException("Request for non-existent listener");
385 }
386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
388 if (mListener != null) {
389 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700390 synchronized (this) {
391 // synchronize to ensure incrementPendingBroadcastsLocked()
392 // is called before decrementPendingBroadcasts()
393 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700394 // call this after broadcasting so we do not increment
395 // if we throw an exeption.
396 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700397 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 } catch (RemoteException e) {
399 return false;
400 }
401 } else {
402 Intent statusChanged = new Intent();
403 statusChanged.putExtras(extras);
404 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
405 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700406 synchronized (this) {
407 // synchronize to ensure incrementPendingBroadcastsLocked()
408 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700409 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700410 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700411 // call this after broadcasting so we do not increment
412 // if we throw an exeption.
413 incrementPendingBroadcastsLocked();
414 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 } catch (PendingIntent.CanceledException e) {
416 return false;
417 }
418 }
419 return true;
420 }
421
422 public boolean callLocationChangedLocked(Location location) {
423 if (mListener != null) {
424 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700425 synchronized (this) {
426 // synchronize to ensure incrementPendingBroadcastsLocked()
427 // is called before decrementPendingBroadcasts()
428 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700429 // call this after broadcasting so we do not increment
430 // if we throw an exeption.
431 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 } catch (RemoteException e) {
434 return false;
435 }
436 } else {
437 Intent locationChanged = new Intent();
438 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
439 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700440 synchronized (this) {
441 // synchronize to ensure incrementPendingBroadcastsLocked()
442 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700443 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700444 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700445 // call this after broadcasting so we do not increment
446 // if we throw an exeption.
447 incrementPendingBroadcastsLocked();
448 }
449 } catch (PendingIntent.CanceledException e) {
450 return false;
451 }
452 }
453 return true;
454 }
455
456 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
457 if (mListener != null) {
458 try {
459 synchronized (this) {
460 // synchronize to ensure incrementPendingBroadcastsLocked()
461 // is called before decrementPendingBroadcasts()
462 if (enabled) {
463 mListener.onProviderEnabled(provider);
464 } else {
465 mListener.onProviderDisabled(provider);
466 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700467 // call this after broadcasting so we do not increment
468 // if we throw an exeption.
469 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700470 }
471 } catch (RemoteException e) {
472 return false;
473 }
474 } else {
475 Intent providerIntent = new Intent();
476 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
477 try {
478 synchronized (this) {
479 // synchronize to ensure incrementPendingBroadcastsLocked()
480 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700481 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700482 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700483 // call this after broadcasting so we do not increment
484 // if we throw an exeption.
485 incrementPendingBroadcastsLocked();
486 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 } catch (PendingIntent.CanceledException e) {
488 return false;
489 }
490 }
491 return true;
492 }
493
Nick Pellyf1be6862012-05-15 10:53:42 -0700494 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700496 if (D) Log.d(TAG, "Location listener died");
497
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400498 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 removeUpdatesLocked(this);
500 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700501 synchronized (this) {
502 if (mPendingBroadcasts > 0) {
503 LocationManagerService.this.decrementPendingBroadcasts();
504 mPendingBroadcasts = 0;
505 }
506 }
507 }
508
Nick Pellye0fd6932012-07-11 10:26:13 -0700509 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700510 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
511 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400512 synchronized (this) {
513 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700514 }
515 }
516
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400517 // this must be called while synchronized by caller in a synchronized block
518 // containing the sending of the broadcaset
519 private void incrementPendingBroadcastsLocked() {
520 if (mPendingBroadcasts++ == 0) {
521 LocationManagerService.this.incrementPendingBroadcasts();
522 }
523 }
524
525 private void decrementPendingBroadcastsLocked() {
526 if (--mPendingBroadcasts == 0) {
527 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700528 }
529 }
530 }
531
Nick Pellye0fd6932012-07-11 10:26:13 -0700532 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700533 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400534 //Do not use getReceiver here as that will add the ILocationListener to
535 //the receiver list if it is not found. If it is not found then the
536 //LocationListener was removed when it had a pending broadcast and should
537 //not be added back.
538 IBinder binder = listener.asBinder();
539 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700540 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400541 synchronized (receiver) {
542 // so wakelock calls will succeed
543 long identity = Binder.clearCallingIdentity();
544 receiver.decrementPendingBroadcastsLocked();
545 Binder.restoreCallingIdentity(identity);
546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 }
548 }
549
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700550 /** Settings Observer callback */
551 @Override
552 public void update(Observable o, Object arg) {
553 synchronized (mLock) {
554 updateProvidersLocked();
Mike Lockwood9637d472009-04-02 21:41:57 -0700555 }
556 }
557
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700558 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400559 mProviders.add(provider);
560 mProvidersByName.put(provider.getName(), provider);
561 }
562
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700563 private void removeProviderLocked(LocationProviderInterface provider) {
564 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400565 mProviders.remove(provider);
566 mProvidersByName.remove(provider.getName());
567 }
568
Mike Lockwood3d12b512009-04-21 23:25:35 -0700569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 private boolean isAllowedBySettingsLocked(String provider) {
571 if (mEnabledProviders.contains(provider)) {
572 return true;
573 }
574 if (mDisabledProviders.contains(provider)) {
575 return false;
576 }
577 // Use system settings
578 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579
Brad Larson8eb3ea62009-12-29 11:47:55 -0600580 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 }
582
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700583 /**
584 * Throw SecurityException if caller has neither COARSE or FINE.
585 * Otherwise, return the best permission.
586 */
587 private String checkPermission() {
588 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
589 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700590 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700591 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
592 PackageManager.PERMISSION_GRANTED) {
593 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700595
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700596 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
597 "ACCESS_FINE_LOCATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 }
599
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700600 /**
601 * Returns all providers by name, including passive, but excluding
602 * fused.
603 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700604 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700606 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700608 ArrayList<String> out;
609 synchronized (mLock) {
610 out = new ArrayList<String>(mProviders.size());
611 for (LocationProviderInterface provider : mProviders) {
612 String name = provider.getName();
613 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700614 continue;
615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 out.add(name);
617 }
618 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700619
620 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 return out;
622 }
623
Mike Lockwood03ca2162010-04-01 08:10:09 -0700624 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700625 * Return all providers by name, that match criteria and are optionally
626 * enabled.
627 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700628 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700629 @Override
630 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
631 checkPermission();
Mike Lockwood03ca2162010-04-01 08:10:09 -0700632
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700633 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700634 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700635 out = new ArrayList<String>(mProviders.size());
636 for (LocationProviderInterface provider : mProviders) {
637 String name = provider.getName();
638 if (LocationManager.FUSED_PROVIDER.equals(name)) {
639 continue;
640 }
641 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
642 continue;
643 }
644 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
645 name, provider.getProperties(), criteria)) {
646 continue;
647 }
648 out.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700649 }
650 }
651
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700652 if (D) Log.d(TAG, "getProviders()=" + out);
653 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700654 }
655
656 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700657 * Return the name of the best provider given a Criteria object.
658 * This method has been deprecated from the public API,
659 * and the whole LoactionProvider (including #meetsCriteria)
660 * has been deprecated as well. So this method now uses
661 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700662 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700663 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700664 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700665 String result = null;
666 checkPermission();
667
668 List<String> providers = getProviders(criteria, enabledOnly);
669 if (providers.size() < 1) {
670 result = pickBest(providers);
671 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
672 return result;
673 }
674 providers = getProviders(null, enabledOnly);
675 if (providers.size() >= 1) {
676 result = pickBest(providers);
677 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
678 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700679 }
680
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700681 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700682 return null;
683 }
684
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700685 private String pickBest(List<String> providers) {
686 if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
687 return LocationManager.NETWORK_PROVIDER;
688 } else if (providers.contains(LocationManager.GPS_PROVIDER)) {
689 return LocationManager.GPS_PROVIDER;
690 } else {
691 return providers.get(0);
692 }
693 }
694
Nick Pellye0fd6932012-07-11 10:26:13 -0700695 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700696 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700697 checkPermission();
698
Mike Lockwood03ca2162010-04-01 08:10:09 -0700699 LocationProviderInterface p = mProvidersByName.get(provider);
700 if (p == null) {
701 throw new IllegalArgumentException("provider=" + provider);
702 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700703
704 boolean result = LocationProvider.propertiesMeetCriteria(
705 p.getName(), p.getProperties(), criteria);
706 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
707 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700708 }
709
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700711 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400712 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500713 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 boolean isEnabled = p.isEnabled();
715 String name = p.getName();
716 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 if (isEnabled && !shouldBeEnabled) {
718 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700719 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 } else if (!isEnabled && shouldBeEnabled) {
721 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700722 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700724 }
725 if (changesMade) {
726 mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 }
728 }
729
730 private void updateProviderListenersLocked(String provider, boolean enabled) {
731 int listeners = 0;
732
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500733 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700734 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735
736 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
739 if (records != null) {
740 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700741 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 UpdateRecord record = records.get(i);
743 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700744 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
745 if (deadReceivers == null) {
746 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 }
Simon Schoar46866572009-06-10 21:12:10 +0200748 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 }
750 listeners++;
751 }
752 }
753
754 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700755 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 removeUpdatesLocked(deadReceivers.get(i));
757 }
758 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 if (enabled) {
761 p.enable();
762 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700763 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 }
765 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 }
769
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700770 private void applyRequirementsLocked(String provider) {
771 LocationProviderInterface p = mProvidersByName.get(provider);
772 if (p == null) return;
773
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700775 WorkSource worksource = new WorkSource();
776 ProviderRequest providerRequest = new ProviderRequest();
777
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700779 for (UpdateRecord record : records) {
780 LocationRequest locationRequest = record.mRequest;
781
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700782 providerRequest.locationRequests.add(locationRequest);
783 if (locationRequest.getInterval() < providerRequest.interval) {
784 providerRequest.reportLocation = true;
785 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700786 }
787 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700788
789 if (providerRequest.reportLocation) {
790 // calculate who to blame for power
791 // This is somewhat arbitrary. We pick a threshold interval
792 // that is slightly higher that the minimum interval, and
793 // spread the blame across all applications with a request
794 // under that threshold.
795 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
796 for (UpdateRecord record : records) {
797 LocationRequest locationRequest = record.mRequest;
798 if (locationRequest.getInterval() <= thresholdInterval) {
799 worksource.add(record.mReceiver.mUid);
800 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700801 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 }
803 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700804
805 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
806 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
808
809 private class UpdateRecord {
810 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700811 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400813 Location mLastFixBroadcast;
814 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815
816 /**
817 * Note: must be constructed with lock held.
818 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700819 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700821 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823
824 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
825 if (records == null) {
826 records = new ArrayList<UpdateRecord>();
827 mRecordsByProvider.put(provider, records);
828 }
829 if (!records.contains(this)) {
830 records.add(this);
831 }
832 }
833
834 /**
835 * Method to be called when a record will no longer be used. Calling this multiple times
836 * must have the same effect as calling it once.
837 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700838 void disposeLocked(boolean removeReceiver) {
839 // remove from mRecordsByProvider
840 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
841 if (globalRecords != null) {
842 globalRecords.remove(this);
843 }
844
845 if (!removeReceiver) return; // the caller will handle the rest
846
847 // remove from Receiver#mUpdateRecords
848 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
849 if (receiverRecords != null) {
850 receiverRecords.remove(this.mProvider);
851
852 // and also remove the Receiver if it has no more update records
853 if (removeReceiver && receiverRecords.size() == 0) {
854 removeUpdatesLocked(mReceiver);
855 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400856 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 }
858
859 @Override
860 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700861 StringBuilder s = new StringBuilder();
862 s.append("UpdateRecord[");
863 s.append(mProvider);
864 s.append(' ').append(mReceiver.mPackageName).append('(');
865 s.append(mReceiver.mUid).append(')');
866 s.append(' ').append(mRequest);
867 s.append(']');
868 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 }
871
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700872 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400873 IBinder binder = listener.asBinder();
874 Receiver receiver = mReceivers.get(binder);
875 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700876 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400877 mReceivers.put(binder, receiver);
878
879 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700880 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400881 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800882 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400883 return null;
884 }
885 }
886 return receiver;
887 }
888
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700889 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400890 Receiver receiver = mReceivers.get(intent);
891 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700892 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400893 mReceivers.put(intent, receiver);
894 }
895 return receiver;
896 }
897
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700898 private String checkPermissionAndRequest(LocationRequest request) {
899 String perm = checkPermission();
900
901 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700902 switch (request.getQuality()) {
903 case LocationRequest.ACCURACY_FINE:
904 request.setQuality(LocationRequest.ACCURACY_BLOCK);
905 break;
906 case LocationRequest.POWER_HIGH:
907 request.setQuality(LocationRequest.POWER_LOW);
908 break;
909 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700910 // throttle
911 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
912 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
913 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700914 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
915 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
916 }
917 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700918 // make getFastestInterval() the minimum of interval and fastest interval
919 if (request.getFastestInterval() > request.getInterval()) {
920 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400921 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700922 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400923 }
924
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700925 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700926 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700927 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700928 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700929 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700930 String[] packages = mPackageManager.getPackagesForUid(uid);
931 if (packages == null) {
932 throw new SecurityException("invalid UID " + uid);
933 }
934 for (String pkg : packages) {
935 if (packageName.equals(pkg)) return;
936 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700937 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700938 }
939
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700940 private void checkPendingIntent(PendingIntent intent) {
941 if (intent == null) {
942 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700943 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700944 }
945
946 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
947 int pid, int uid, String packageName) {
948 if (intent == null && listener == null) {
949 throw new IllegalArgumentException("need eiter listener or intent");
950 } else if (intent != null && listener != null) {
951 throw new IllegalArgumentException("cannot register both listener and intent");
952 } else if (intent != null) {
953 checkPendingIntent(intent);
954 return getReceiver(intent, pid, uid, packageName);
955 } else {
956 return getReceiver(listener, pid, uid, packageName);
957 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700958 }
959
Nick Pellye0fd6932012-07-11 10:26:13 -0700960 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700961 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
962 PendingIntent intent, String packageName) {
963 if (request == null) request = DEFAULT_LOCATION_REQUEST;
964 checkPackageName(packageName);
965 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700967 final int pid = Binder.getCallingPid();
968 final int uid = Binder.getCallingUid();
969 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970
Nick Pelly2b7a0d02012-08-17 15:09:44 -0700971 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 long identity = Binder.clearCallingIdentity();
973 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700974 synchronized (mLock) {
975 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400976 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 } finally {
978 Binder.restoreCallingIdentity(identity);
979 }
980 }
981
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700982 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
983 int pid, int uid, String packageName) {
984 // Figure out the provider. Either its explicitly request (legacy use cases), or
985 // use the fused provider
986 if (request == null) request = DEFAULT_LOCATION_REQUEST;
987 String name = request.getProvider();
988 if (name == null) name = LocationManager.FUSED_PROVIDER;
989 LocationProviderInterface provider = mProvidersByName.get(name);
990 if (provider == null) {
991 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
992 }
993
994 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
995 name + " " + request + " from " + packageName + "(" + uid + ")");
996
997 UpdateRecord record = new UpdateRecord(name, request, receiver);
998 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
999 if (oldRecord != null) {
1000 oldRecord.disposeLocked(false);
1001 }
1002
1003 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1004 if (isProviderEnabled) {
1005 applyRequirementsLocked(name);
1006 } else {
1007 // Notify the listener that updates are currently disabled
1008 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 }
1010 }
1011
Nick Pellye0fd6932012-07-11 10:26:13 -07001012 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001013 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1014 String packageName) {
1015 checkPackageName(packageName);
1016 checkPermission();
1017 final int pid = Binder.getCallingPid();
1018 final int uid = Binder.getCallingUid();
1019 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1020
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001021 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001022 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001024 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001025 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001027 } finally {
1028 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 }
1030 }
1031
1032 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001033 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1034
1035 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1036 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1037 synchronized (receiver) {
1038 if (receiver.mPendingBroadcasts > 0) {
1039 decrementPendingBroadcasts();
1040 receiver.mPendingBroadcasts = 0;
1041 }
1042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 }
1044
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001045 // Record which providers were associated with this listener
1046 HashSet<String> providers = new HashSet<String>();
1047 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1048 if (oldRecords != null) {
1049 // Call dispose() on the obsolete update records.
1050 for (UpdateRecord record : oldRecords.values()) {
1051 record.disposeLocked(false);
1052 }
1053 // Accumulate providers
1054 providers.addAll(oldRecords.keySet());
1055 }
1056
1057 // update provider
1058 for (String provider : providers) {
1059 // If provider is already disabled, don't need to do anything
1060 if (!isAllowedBySettingsLocked(provider)) {
1061 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 }
1063
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001064 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 }
1066 }
1067
Nick Pellye0fd6932012-07-11 10:26:13 -07001068 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001069 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001070 if (D) Log.d(TAG, "getLastLocation: " + request);
1071 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1072 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001073 checkPackageName(packageName);
1074
1075 if (mBlacklist.isBlacklisted(packageName)) {
1076 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1077 packageName);
1078 return null;
1079 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001080
1081 synchronized (mLock) {
1082 // Figure out the provider. Either its explicitly request (deprecated API's),
1083 // or use the fused provider
1084 String name = request.getProvider();
1085 if (name == null) name = LocationManager.FUSED_PROVIDER;
1086 LocationProviderInterface provider = mProvidersByName.get(name);
1087 if (provider == null) return null;
1088
1089 if (!isAllowedBySettingsLocked(name)) return null;
1090
1091 Location location = mLastLocation.get(name);
1092 if (ACCESS_FINE_LOCATION.equals(perm)) {
1093 return location;
1094 } else {
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001095 return mLocationFudger.getOrCreate(location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001096 }
1097 }
1098 }
1099
1100 @Override
1101 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1102 String packageName) {
1103 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1104 checkPermissionAndRequest(request);
1105 checkPendingIntent(intent);
1106 checkPackageName(packageName);
1107
1108 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1109
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001110 // geo-fence manager uses the public location API, need to clear identity
1111 int uid = Binder.getCallingUid();
1112 long identity = Binder.clearCallingIdentity();
1113 try {
1114 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1115 } finally {
1116 Binder.restoreCallingIdentity(identity);
1117 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001118 }
1119
1120 @Override
1121 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1122 checkPermission();
1123 checkPendingIntent(intent);
1124 checkPackageName(packageName);
1125
1126 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1127
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001128 // geo-fence manager uses the public location API, need to clear identity
1129 long identity = Binder.clearCallingIdentity();
1130 try {
1131 mGeofenceManager.removeFence(geofence, intent);
1132 } finally {
1133 Binder.restoreCallingIdentity(identity);
1134 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001135 }
1136
1137
1138 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001140 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001141 return false;
1142 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001143 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 PackageManager.PERMISSION_GRANTED) {
1145 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1146 }
1147
1148 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001149 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001151 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 return false;
1153 }
1154 return true;
1155 }
1156
Nick Pellye0fd6932012-07-11 10:26:13 -07001157 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001159 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001160 try {
1161 mGpsStatusProvider.removeGpsStatusListener(listener);
1162 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001163 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001164 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 }
1166 }
1167
Nick Pellye0fd6932012-07-11 10:26:13 -07001168 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001170 if (provider == null) {
1171 // throw NullPointerException to remain compatible with previous implementation
1172 throw new NullPointerException();
1173 }
1174
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001175 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001177 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 != PackageManager.PERMISSION_GRANTED)) {
1179 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1180 }
1181
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001182 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001183 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001184 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001185
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001186 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 }
1188 }
1189
Nick Pellye0fd6932012-07-11 10:26:13 -07001190 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001191 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001192 if (Binder.getCallingUid() != Process.myUid()) {
1193 throw new SecurityException(
1194 "calling sendNiResponse from outside of the system is not allowed");
1195 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001196 try {
1197 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001198 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001199 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001200 return false;
1201 }
1202 }
1203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001205 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001206 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 * accessed by the caller
1208 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001209 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001210 public ProviderProperties getProviderProperties(String provider) {
1211 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001213 LocationProviderInterface p;
1214 synchronized (mLock) {
1215 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 }
1217
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001218 if (p == null) return null;
1219 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 }
1221
Nick Pellye0fd6932012-07-11 10:26:13 -07001222 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001224 checkPermission();
1225 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1226
1227 synchronized (mLock) {
1228 LocationProviderInterface p = mProvidersByName.get(provider);
1229 if (p == null) return false;
1230
1231 return isAllowedBySettingsLocked(provider);
1232 }
1233 }
1234
1235 private void checkCallerIsProvider() {
1236 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1237 == PackageManager.PERMISSION_GRANTED) {
1238 return;
1239 }
1240
1241 // Previously we only used the INSTALL_LOCATION_PROVIDER
1242 // check. But that is system or signature
1243 // protection level which is not flexible enough for
1244 // providers installed oustide the system image. So
1245 // also allow providers with a UID matching the
1246 // currently bound package name
1247
1248 int uid = Binder.getCallingUid();
1249
1250 if (mGeocodeProvider != null) {
1251 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1252 }
1253 for (LocationProviderProxy proxy : mProxyProviders) {
1254 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1255 }
1256 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1257 "or UID of a currently bound location provider");
1258 }
1259
1260 private boolean doesPackageHaveUid(int uid, String packageName) {
1261 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 return false;
1263 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001264 try {
1265 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1266 if (appInfo.uid != uid) {
1267 return false;
1268 }
1269 } catch (NameNotFoundException e) {
1270 return false;
1271 }
1272 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 }
1274
Nick Pellye0fd6932012-07-11 10:26:13 -07001275 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001276 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001277 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001278
Nick Pelly2eeeec22012-07-18 13:13:37 -07001279 if (!location.isComplete()) {
1280 Log.w(TAG, "Dropping incomplete location: " + location);
1281 return;
1282 }
1283
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1285 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001286 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001287 mLocationHandler.sendMessageAtFrontOfQueue(m);
1288 }
1289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290
1291 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1292 // Always broadcast the first update
1293 if (lastLoc == null) {
1294 return true;
1295 }
1296
Nick Pellyf1be6862012-05-15 10:53:42 -07001297 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001298 long minTime = record.mRequest.getFastestInterval();
Nick Pelly2eeeec22012-07-18 13:13:37 -07001299 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001300 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 return false;
1302 }
1303
1304 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001305 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 if (minDistance > 0.0) {
1307 if (loc.distanceTo(lastLoc) <= minDistance) {
1308 return false;
1309 }
1310 }
1311
1312 return true;
1313 }
1314
Mike Lockwooda4903f22010-02-17 06:42:23 -05001315 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001316 if (D) Log.d(TAG, "incoming location: " + location);
1317
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001318 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001319 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001321 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001323 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324 if (p == null) return;
1325
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001326 // Add the coarse location as an extra
1327 Location coarse = mLocationFudger.getOrCreate(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001329 // Update last known locations
1330 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001331 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001332 lastLocation = new Location(provider);
1333 mLastLocation.put(provider, lastLocation);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001334 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001335 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 // Fetch latest status update time
1338 long newStatusUpdateTime = p.getStatusUpdateTime();
1339
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001340 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 Bundle extras = new Bundle();
1342 int status = p.getStatus(extras);
1343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001345 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001348 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001350 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001351
1352 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1353 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1354 receiver.mPackageName);
1355 continue;
1356 }
1357
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001358 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1359 location = lastLocation; // use fine location
1360 } else {
1361 location = coarse; // use coarse location
1362 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001364 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001365 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1366 if (lastLoc == null) {
1367 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001368 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001369 } else {
1370 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001372 if (!receiver.callLocationChangedLocked(location)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001373 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001374 receiverDead = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 }
1376 }
1377
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001378 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1380 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1381
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001382 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001384 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001385 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001386 }
1387 }
1388
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001389 // track expired records
1390 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1391 if (deadUpdateRecords == null) {
1392 deadUpdateRecords = new ArrayList<UpdateRecord>();
1393 }
1394 deadUpdateRecords.add(r);
1395 }
1396 // track dead receivers
1397 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001398 if (deadReceivers == null) {
1399 deadReceivers = new ArrayList<Receiver>();
1400 }
1401 if (!deadReceivers.contains(receiver)) {
1402 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 }
1404 }
1405 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001406
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001407 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001409 for (Receiver receiver : deadReceivers) {
1410 removeUpdatesLocked(receiver);
1411 }
1412 }
1413 if (deadUpdateRecords != null) {
1414 for (UpdateRecord r : deadUpdateRecords) {
1415 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 }
1417 }
1418 }
1419
1420 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 @Override
1422 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001423 switch (msg.what) {
1424 case MSG_LOCATION_CHANGED:
1425 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1426 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 }
1428 }
1429 }
1430
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001431 private void handleLocationChanged(Location location, boolean passive) {
1432 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001433
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001434 if (!passive) {
1435 // notify passive provider of the new location
1436 mPassiveProvider.updateLocation(location);
1437 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001439 synchronized (mLock) {
1440 if (isAllowedBySettingsLocked(provider)) {
1441 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001444 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445
Mike Lockwoode97ae402010-09-29 15:23:46 -04001446 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1447 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001448 public void onPackageDisappeared(String packageName, int reason) {
1449 // remove all receivers associated with this package name
1450 synchronized (mLock) {
1451 ArrayList<Receiver> deadReceivers = null;
1452
1453 for (Receiver receiver : mReceivers.values()) {
1454 if (receiver.mPackageName.equals(packageName)) {
1455 if (deadReceivers == null) {
1456 deadReceivers = new ArrayList<Receiver>();
1457 }
1458 deadReceivers.add(receiver);
1459 }
1460 }
1461
1462 // perform removal outside of mReceivers loop
1463 if (deadReceivers != null) {
1464 for (Receiver receiver : deadReceivers) {
1465 removeUpdatesLocked(receiver);
1466 }
1467 }
1468 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001469 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001470 };
1471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 // Wake locks
1473
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001474 private void incrementPendingBroadcasts() {
1475 synchronized (mWakeLock) {
1476 if (mPendingBroadcasts++ == 0) {
1477 try {
1478 mWakeLock.acquire();
1479 log("Acquired wakelock");
1480 } catch (Exception e) {
1481 // This is to catch a runtime exception thrown when we try to release an
1482 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001483 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001484 }
1485 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001486 }
1487 }
1488
1489 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001490 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001491 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001492 try {
1493 // Release wake lock
1494 if (mWakeLock.isHeld()) {
1495 mWakeLock.release();
1496 log("Released wakelock");
1497 } else {
1498 log("Can't release wakelock again!");
1499 }
1500 } catch (Exception e) {
1501 // This is to catch a runtime exception thrown when we try to release an
1502 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001503 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001504 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001505 }
1506 }
1507 }
1508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 // Geocoder
1510
Nick Pellye0fd6932012-07-11 10:26:13 -07001511 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001512 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001513 return mGeocodeProvider != null;
1514 }
1515
Nick Pellye0fd6932012-07-11 10:26:13 -07001516 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001518 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001519 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001520 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1521 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001523 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 }
1525
Mike Lockwooda55c3212009-04-15 11:10:11 -04001526
Nick Pellye0fd6932012-07-11 10:26:13 -07001527 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001529 double lowerLeftLatitude, double lowerLeftLongitude,
1530 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001531 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001532
1533 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001534 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1535 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1536 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001538 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 }
1540
1541 // Mock Providers
1542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 private void checkMockPermissionsSafe() {
1544 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1545 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1546 if (!allowMocks) {
1547 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1548 }
1549
1550 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1551 PackageManager.PERMISSION_GRANTED) {
1552 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001553 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 }
1555
Nick Pellye0fd6932012-07-11 10:26:13 -07001556 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001557 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 checkMockPermissionsSafe();
1559
Mike Lockwooda4903f22010-02-17 06:42:23 -05001560 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1561 throw new IllegalArgumentException("Cannot mock the passive location provider");
1562 }
1563
Mike Lockwood86328a92009-10-23 08:38:25 -04001564 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001565 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001566 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001567 // remove the real provider if we are replacing GPS or network provider
1568 if (LocationManager.GPS_PROVIDER.equals(name)
1569 || LocationManager.NETWORK_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001570 LocationProviderInterface p = mProvidersByName.get(name);
1571 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001572 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001573 }
1574 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001575 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1577 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001578 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001579 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001580 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 updateProvidersLocked();
1582 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001583 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 }
1585
Nick Pellye0fd6932012-07-11 10:26:13 -07001586 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 public void removeTestProvider(String provider) {
1588 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001589 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001590 MockProvider mockProvider = mMockProviders.get(provider);
1591 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1593 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001594 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001595 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001596 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001597
1598 // reinstate real provider if available
1599 LocationProviderInterface realProvider = mRealProviders.get(provider);
1600 if (realProvider != null) {
1601 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001602 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001603 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001605 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 }
1607 }
1608
Nick Pellye0fd6932012-07-11 10:26:13 -07001609 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 public void setTestProviderLocation(String provider, Location loc) {
1611 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001612 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001613 MockProvider mockProvider = mMockProviders.get(provider);
1614 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1616 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001617 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1618 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001619 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001620 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 }
1622 }
1623
Nick Pellye0fd6932012-07-11 10:26:13 -07001624 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 public void clearTestProviderLocation(String provider) {
1626 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001627 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001628 MockProvider mockProvider = mMockProviders.get(provider);
1629 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1631 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001632 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 }
1634 }
1635
Nick Pellye0fd6932012-07-11 10:26:13 -07001636 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001637 public void setTestProviderEnabled(String provider, boolean enabled) {
1638 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001639 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001640 MockProvider mockProvider = mMockProviders.get(provider);
1641 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1643 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001644 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001646 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 mEnabledProviders.add(provider);
1648 mDisabledProviders.remove(provider);
1649 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001650 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 mEnabledProviders.remove(provider);
1652 mDisabledProviders.add(provider);
1653 }
1654 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001655 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 }
1657 }
1658
Nick Pellye0fd6932012-07-11 10:26:13 -07001659 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 public void clearTestProviderEnabled(String provider) {
1661 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001662 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001663 MockProvider mockProvider = mMockProviders.get(provider);
1664 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1666 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001667 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 mEnabledProviders.remove(provider);
1669 mDisabledProviders.remove(provider);
1670 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001671 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 }
1673 }
1674
Nick Pellye0fd6932012-07-11 10:26:13 -07001675 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1677 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001678 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001679 MockProvider mockProvider = mMockProviders.get(provider);
1680 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1682 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001683 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 }
1685 }
1686
Nick Pellye0fd6932012-07-11 10:26:13 -07001687 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 public void clearTestProviderStatus(String provider) {
1689 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001690 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001691 MockProvider mockProvider = mMockProviders.get(provider);
1692 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1694 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001695 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 }
1697 }
1698
1699 private void log(String log) {
1700 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001701 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 }
1703 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001704
1705 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1707 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1708 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001709 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 + Binder.getCallingPid()
1711 + ", uid=" + Binder.getCallingUid());
1712 return;
1713 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001714
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001715 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001718 for (Receiver receiver : mReceivers.values()) {
1719 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001722 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1723 pw.println(" " + entry.getKey() + ":");
1724 for (UpdateRecord record : entry.getValue()) {
1725 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 }
1727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001729 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1730 String provider = entry.getKey();
1731 Location location = entry.getValue();
1732 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001734
Nick Pellye0fd6932012-07-11 10:26:13 -07001735 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001736
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 if (mEnabledProviders.size() > 0) {
1738 pw.println(" Enabled Providers:");
1739 for (String i : mEnabledProviders) {
1740 pw.println(" " + i);
1741 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 }
1744 if (mDisabledProviders.size() > 0) {
1745 pw.println(" Disabled Providers:");
1746 for (String i : mDisabledProviders) {
1747 pw.println(" " + i);
1748 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001749 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001750 pw.append(" ");
1751 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 if (mMockProviders.size() > 0) {
1753 pw.println(" Mock Providers:");
1754 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001755 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 }
1757 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001758
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001759 pw.append(" fudger: ");
1760 mLocationFudger.dump(fd, pw, args);
1761
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001762 if (args.length > 0 && "short".equals(args[0])) {
1763 return;
1764 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001765 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001766 pw.print(provider.getName() + " Internal State");
1767 if (provider instanceof LocationProviderProxy) {
1768 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1769 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001770 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001771 pw.println(":");
1772 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001773 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 }
1775 }
1776}