blob: 05d11b928ad90dabc87bc3efc6395924885ae531 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.PendingIntent;
Mike Lockwood9637d472009-04-02 21:41:57 -070020import android.content.ContentQueryMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070027import android.content.pm.PackageManager.NameNotFoundException;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050028import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070029import android.database.ContentObserver;
Mike Lockwood9637d472009-04-02 21:41:57 -070030import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070032import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050033import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070034import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040036import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.location.ILocationListener;
38import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040039import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.location.Location;
41import android.location.LocationManager;
42import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070043import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.net.ConnectivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.Binder;
46import android.os.Bundle;
47import android.os.Handler;
48import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070049import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.Message;
51import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070052import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070054import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070055import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070056import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.provider.Settings;
Nick Pellye0fd6932012-07-11 10:26:13 -070058import android.provider.Settings.NameValueTable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080060import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
Mike Lockwoode97ae402010-09-29 15:23:46 -040062import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070063import com.android.internal.location.ProviderProperties;
64import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040065import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070066import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040067import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070068import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070069import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040070import com.android.server.location.LocationProviderInterface;
71import com.android.server.location.LocationProviderProxy;
72import com.android.server.location.MockProvider;
73import com.android.server.location.PassiveProvider;
74
75import java.io.FileDescriptor;
76import java.io.PrintWriter;
77import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070078import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040079import java.util.HashMap;
80import java.util.HashSet;
81import java.util.List;
82import java.util.Map;
83import java.util.Observable;
84import java.util.Observer;
85import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
87/**
88 * The service class that manages LocationProviders and issues location
89 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 */
Brian Muramatsubb95cb92012-08-29 10:43:21 -070091public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070093 public static final boolean D = false;
94
95 private static final String WAKELOCK_KEY = TAG;
96 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 private static final String ACCESS_FINE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070099 android.Manifest.permission.ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private static final String ACCESS_COARSE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700101 android.Manifest.permission.ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700103 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700105 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400106 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700107 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
108
109 private static final String NETWORK_LOCATION_SERVICE_ACTION =
110 "com.android.location.service.v2.NetworkLocationProvider";
111 private static final String FUSED_LOCATION_SERVICE_ACTION =
112 "com.android.location.service.FusedLocationProvider";
113
114 private static final int MSG_LOCATION_CHANGED = 1;
115
Nick Pellyf1be6862012-05-15 10:53:42 -0700116 // Location Providers may sometimes deliver location updates
117 // slightly faster that requested - provide grace period so
118 // we don't unnecessarily filter events that are otherwise on
119 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700120 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700121
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700122 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
123
124 private final Context mContext;
125
126 // used internally for synchronization
127 private final Object mLock = new Object();
128
129 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700130 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700131 private GeofenceManager mGeofenceManager;
132 private PowerManager.WakeLock mWakeLock;
133 private PackageManager mPackageManager;
134 private GeocoderProxy mGeocodeProvider;
135 private IGpsStatusProvider mGpsStatusProvider;
136 private INetInitiatedListener mNetInitiatedListener;
137 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700138 private PassiveProvider mPassiveProvider; // track passive provider for special cases
139 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700140
141 // --- fields below are protected by mWakeLock ---
142 private int mPendingBroadcasts;
143
144 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 // Set of providers that are explicitly enabled
146 private final Set<String> mEnabledProviders = new HashSet<String>();
147
148 // Set of providers that are explicitly disabled
149 private final Set<String> mDisabledProviders = new HashSet<String>();
150
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700151 // Mock (test) providers
152 private final HashMap<String, MockProvider> mMockProviders =
153 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400156 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700158 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500159 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400161
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700162 // real providers, saved here when mocked out
163 private final HashMap<String, LocationProviderInterface> mRealProviders =
164 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700166 // mapping from provider name to provider
167 private final HashMap<String, LocationProviderInterface> mProvidersByName =
168 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700170 // mapping from provider name to all its UpdateRecords
171 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
172 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700173
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174 // mapping from provider name to last known location
175 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 // all providers that operate over proxy, for authorizing incoming location
178 private final ArrayList<LocationProviderProxy> mProxyProviders =
179 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 public LocationManagerService(Context context) {
182 super();
183 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800184
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 if (D) Log.d(TAG, "Constructed");
186
187 // most startup is deferred until systemReady()
188 }
189
190 public void systemReady() {
191 Thread thread = new Thread(null, this, THREAD_NAME);
192 thread.start();
193 }
194
195 @Override
196 public void run() {
197 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
198 Looper.prepare();
199 mLocationHandler = new LocationWorkerHandler();
200 init();
201 Looper.loop();
202 }
203
204 private void init() {
205 if (D) Log.d(TAG, "init()");
206
207 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
208 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
209 mPackageManager = mContext.getPackageManager();
210
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700211 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
212 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700213 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700214
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700215 synchronized (mLock) {
216 loadProvidersLocked();
217 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700218
Nick Pelly4035f5a2012-08-17 14:43:49 -0700219 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700220
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700221 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700222 mContext.getContentResolver().registerContentObserver(
223 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
224 new ContentObserver(mLocationHandler) {
225 @Override
226 public void onChange(boolean selfChange) {
227 synchronized (mLock) {
228 updateProvidersLocked();
229 }
230 }
231 });
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700232 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700233
234 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700235 }
236
237 private void loadProvidersLocked() {
238 if (GpsLocationProvider.isSupported()) {
239 // Create a gps location provider
240 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
241 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
242 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
243 addProviderLocked(gpsProvider);
244 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
245 }
246
247 // create a passive location provider, which is always enabled
248 PassiveProvider passiveProvider = new PassiveProvider(this);
249 addProviderLocked(passiveProvider);
250 mEnabledProviders.add(passiveProvider.getName());
251 mPassiveProvider = passiveProvider;
252
253 /*
254 Load package name(s) containing location provider support.
255 These packages can contain services implementing location providers:
256 Geocoder Provider, Network Location Provider, and
257 Fused Location Provider. They will each be searched for
258 service components implementing these providers.
259 The location framework also has support for installation
260 of new location providers at run-time. The new package does not
261 have to be explicitly listed here, however it must have a signature
262 that matches the signature of at least one package on this list.
263 */
264 Resources resources = mContext.getResources();
265 ArrayList<String> providerPackageNames = new ArrayList<String>();
266 String[] pkgs1 = resources.getStringArray(
267 com.android.internal.R.array.config_locationProviderPackageNames);
268 String[] pkgs2 = resources.getStringArray(
269 com.android.internal.R.array.config_overlay_locationProviderPackageNames);
270 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
271 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
272 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
273 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
274
275 // bind to network provider
276 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
277 mContext,
278 LocationManager.NETWORK_PROVIDER,
279 NETWORK_LOCATION_SERVICE_ACTION,
280 providerPackageNames, mLocationHandler);
281 if (networkProvider != null) {
282 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
283 mProxyProviders.add(networkProvider);
284 addProviderLocked(networkProvider);
285 } else {
286 Slog.w(TAG, "no network location provider found");
287 }
288
289 // bind to fused provider
290 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
291 mContext,
292 LocationManager.FUSED_PROVIDER,
293 FUSED_LOCATION_SERVICE_ACTION,
294 providerPackageNames, mLocationHandler);
295 if (fusedLocationProvider != null) {
296 addProviderLocked(fusedLocationProvider);
297 mProxyProviders.add(fusedLocationProvider);
298 mEnabledProviders.add(fusedLocationProvider.getName());
299 } else {
300 Slog.e(TAG, "no fused location provider found",
301 new IllegalStateException("Location service needs a fused location provider"));
302 }
303
304 // bind to geocoder provider
305 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
306 if (mGeocodeProvider == null) {
307 Slog.e(TAG, "no geocoder provider found");
308 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700309 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 /**
312 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
313 * location updates.
314 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700315 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700316 final int mUid; // uid of receiver
317 final int mPid; // pid of receiver
318 final String mPackageName; // package name of receiver
319 final String mPermission; // best permission that receiver has
320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 final ILocationListener mListener;
322 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700324
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400325 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700326
Mike Lockwood48f17512009-04-23 09:12:08 -0700327 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700329 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
330 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700333 if (listener != null) {
334 mKey = listener.asBinder();
335 } else {
336 mKey = intent;
337 }
338 mPermission = checkPermission();
339 mUid = uid;
340 mPid = pid;
341 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 }
343
344 @Override
345 public boolean equals(Object otherObj) {
346 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700347 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 }
349 return false;
350 }
351
352 @Override
353 public int hashCode() {
354 return mKey.hashCode();
355 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 @Override
358 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700359 StringBuilder s = new StringBuilder();
360 s.append("Reciever[");
361 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700363 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700365 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700367 for (String p : mUpdateRecords.keySet()) {
368 s.append(" ").append(mUpdateRecords.get(p).toString());
369 }
370 s.append("]");
371 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 }
373
374 public boolean isListener() {
375 return mListener != null;
376 }
377
378 public boolean isPendingIntent() {
379 return mPendingIntent != null;
380 }
381
382 public ILocationListener getListener() {
383 if (mListener != null) {
384 return mListener;
385 }
386 throw new IllegalStateException("Request for non-existent listener");
387 }
388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
390 if (mListener != null) {
391 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700392 synchronized (this) {
393 // synchronize to ensure incrementPendingBroadcastsLocked()
394 // is called before decrementPendingBroadcasts()
395 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700396 // call this after broadcasting so we do not increment
397 // if we throw an exeption.
398 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700399 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 } catch (RemoteException e) {
401 return false;
402 }
403 } else {
404 Intent statusChanged = new Intent();
405 statusChanged.putExtras(extras);
406 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
407 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700408 synchronized (this) {
409 // synchronize to ensure incrementPendingBroadcastsLocked()
410 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700411 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700412 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700413 // call this after broadcasting so we do not increment
414 // if we throw an exeption.
415 incrementPendingBroadcastsLocked();
416 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 } catch (PendingIntent.CanceledException e) {
418 return false;
419 }
420 }
421 return true;
422 }
423
424 public boolean callLocationChangedLocked(Location location) {
425 if (mListener != null) {
426 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700427 synchronized (this) {
428 // synchronize to ensure incrementPendingBroadcastsLocked()
429 // is called before decrementPendingBroadcasts()
430 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700431 // call this after broadcasting so we do not increment
432 // if we throw an exeption.
433 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700434 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 } catch (RemoteException e) {
436 return false;
437 }
438 } else {
439 Intent locationChanged = new Intent();
440 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
441 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700442 synchronized (this) {
443 // synchronize to ensure incrementPendingBroadcastsLocked()
444 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700445 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700446 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700447 // call this after broadcasting so we do not increment
448 // if we throw an exeption.
449 incrementPendingBroadcastsLocked();
450 }
451 } catch (PendingIntent.CanceledException e) {
452 return false;
453 }
454 }
455 return true;
456 }
457
458 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
459 if (mListener != null) {
460 try {
461 synchronized (this) {
462 // synchronize to ensure incrementPendingBroadcastsLocked()
463 // is called before decrementPendingBroadcasts()
464 if (enabled) {
465 mListener.onProviderEnabled(provider);
466 } else {
467 mListener.onProviderDisabled(provider);
468 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700469 // call this after broadcasting so we do not increment
470 // if we throw an exeption.
471 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700472 }
473 } catch (RemoteException e) {
474 return false;
475 }
476 } else {
477 Intent providerIntent = new Intent();
478 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
479 try {
480 synchronized (this) {
481 // synchronize to ensure incrementPendingBroadcastsLocked()
482 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700483 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700484 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700485 // call this after broadcasting so we do not increment
486 // if we throw an exeption.
487 incrementPendingBroadcastsLocked();
488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 } catch (PendingIntent.CanceledException e) {
490 return false;
491 }
492 }
493 return true;
494 }
495
Nick Pellyf1be6862012-05-15 10:53:42 -0700496 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700498 if (D) Log.d(TAG, "Location listener died");
499
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400500 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 removeUpdatesLocked(this);
502 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700503 synchronized (this) {
504 if (mPendingBroadcasts > 0) {
505 LocationManagerService.this.decrementPendingBroadcasts();
506 mPendingBroadcasts = 0;
507 }
508 }
509 }
510
Nick Pellye0fd6932012-07-11 10:26:13 -0700511 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700512 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
513 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400514 synchronized (this) {
515 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700516 }
517 }
518
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400519 // this must be called while synchronized by caller in a synchronized block
520 // containing the sending of the broadcaset
521 private void incrementPendingBroadcastsLocked() {
522 if (mPendingBroadcasts++ == 0) {
523 LocationManagerService.this.incrementPendingBroadcasts();
524 }
525 }
526
527 private void decrementPendingBroadcastsLocked() {
528 if (--mPendingBroadcasts == 0) {
529 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700530 }
531 }
532 }
533
Nick Pellye0fd6932012-07-11 10:26:13 -0700534 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700535 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400536 //Do not use getReceiver here as that will add the ILocationListener to
537 //the receiver list if it is not found. If it is not found then the
538 //LocationListener was removed when it had a pending broadcast and should
539 //not be added back.
540 IBinder binder = listener.asBinder();
541 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700542 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400543 synchronized (receiver) {
544 // so wakelock calls will succeed
545 long identity = Binder.clearCallingIdentity();
546 receiver.decrementPendingBroadcastsLocked();
547 Binder.restoreCallingIdentity(identity);
548 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 }
550 }
551
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700552 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400553 mProviders.add(provider);
554 mProvidersByName.put(provider.getName(), provider);
555 }
556
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700557 private void removeProviderLocked(LocationProviderInterface provider) {
558 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400559 mProviders.remove(provider);
560 mProvidersByName.remove(provider.getName());
561 }
562
Mike Lockwood3d12b512009-04-21 23:25:35 -0700563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 private boolean isAllowedBySettingsLocked(String provider) {
565 if (mEnabledProviders.contains(provider)) {
566 return true;
567 }
568 if (mDisabledProviders.contains(provider)) {
569 return false;
570 }
571 // Use system settings
572 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573
Brad Larson8eb3ea62009-12-29 11:47:55 -0600574 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 }
576
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700577 /**
578 * Throw SecurityException if caller has neither COARSE or FINE.
579 * Otherwise, return the best permission.
580 */
581 private String checkPermission() {
582 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
583 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700584 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700585 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
586 PackageManager.PERMISSION_GRANTED) {
587 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700589
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700590 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
Victoria Lease4fab68b2012-09-13 13:20:59 -0700591 " ACCESS_FINE_LOCATION permission");
592 }
593
594 /**
595 * Throw SecurityException if caller lacks permission to use Geofences.
596 */
597 private void checkGeofencePermission() {
598 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
599 PackageManager.PERMISSION_GRANTED) {
600 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
601 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 }
603
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700604 /**
605 * Returns all providers by name, including passive, but excluding
606 * fused.
607 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700608 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700610 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700612 ArrayList<String> out;
613 synchronized (mLock) {
614 out = new ArrayList<String>(mProviders.size());
615 for (LocationProviderInterface provider : mProviders) {
616 String name = provider.getName();
617 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700618 continue;
619 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 out.add(name);
621 }
622 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700623
624 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 return out;
626 }
627
Mike Lockwood03ca2162010-04-01 08:10:09 -0700628 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700629 * Return all providers by name, that match criteria and are optionally
630 * enabled.
631 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700632 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700633 @Override
634 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
635 checkPermission();
Mike Lockwood03ca2162010-04-01 08:10:09 -0700636
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700637 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700638 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700639 out = new ArrayList<String>(mProviders.size());
640 for (LocationProviderInterface provider : mProviders) {
641 String name = provider.getName();
642 if (LocationManager.FUSED_PROVIDER.equals(name)) {
643 continue;
644 }
645 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
646 continue;
647 }
648 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
649 name, provider.getProperties(), criteria)) {
650 continue;
651 }
652 out.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700653 }
654 }
655
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700656 if (D) Log.d(TAG, "getProviders()=" + out);
657 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700658 }
659
660 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 * Return the name of the best provider given a Criteria object.
662 * This method has been deprecated from the public API,
663 * and the whole LoactionProvider (including #meetsCriteria)
664 * has been deprecated as well. So this method now uses
665 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700666 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700667 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700668 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700669 String result = null;
670 checkPermission();
671
672 List<String> providers = getProviders(criteria, enabledOnly);
673 if (providers.size() < 1) {
674 result = pickBest(providers);
675 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
676 return result;
677 }
678 providers = getProviders(null, enabledOnly);
679 if (providers.size() >= 1) {
680 result = pickBest(providers);
681 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
682 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700683 }
684
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700685 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700686 return null;
687 }
688
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700689 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700690 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700691 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700692 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
693 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700694 } else {
695 return providers.get(0);
696 }
697 }
698
Nick Pellye0fd6932012-07-11 10:26:13 -0700699 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700700 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700701 checkPermission();
702
Mike Lockwood03ca2162010-04-01 08:10:09 -0700703 LocationProviderInterface p = mProvidersByName.get(provider);
704 if (p == null) {
705 throw new IllegalArgumentException("provider=" + provider);
706 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700707
708 boolean result = LocationProvider.propertiesMeetCriteria(
709 p.getName(), p.getProperties(), criteria);
710 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
711 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700712 }
713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700715 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400716 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500717 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 boolean isEnabled = p.isEnabled();
719 String name = p.getName();
720 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 if (isEnabled && !shouldBeEnabled) {
722 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700723 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 } else if (!isEnabled && shouldBeEnabled) {
725 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700726 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700728 }
729 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700730 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
731 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 }
733 }
734
735 private void updateProviderListenersLocked(String provider, boolean enabled) {
736 int listeners = 0;
737
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500738 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700739 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740
741 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
744 if (records != null) {
745 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700746 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 UpdateRecord record = records.get(i);
748 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700749 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
750 if (deadReceivers == null) {
751 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 }
Simon Schoar46866572009-06-10 21:12:10 +0200753 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 }
755 listeners++;
756 }
757 }
758
759 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700760 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 removeUpdatesLocked(deadReceivers.get(i));
762 }
763 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 if (enabled) {
766 p.enable();
767 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700768 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 }
770 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 }
774
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700775 private void applyRequirementsLocked(String provider) {
776 LocationProviderInterface p = mProvidersByName.get(provider);
777 if (p == null) return;
778
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700780 WorkSource worksource = new WorkSource();
781 ProviderRequest providerRequest = new ProviderRequest();
782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700784 for (UpdateRecord record : records) {
785 LocationRequest locationRequest = record.mRequest;
786
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700787 providerRequest.locationRequests.add(locationRequest);
788 if (locationRequest.getInterval() < providerRequest.interval) {
789 providerRequest.reportLocation = true;
790 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700791 }
792 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700793
794 if (providerRequest.reportLocation) {
795 // calculate who to blame for power
796 // This is somewhat arbitrary. We pick a threshold interval
797 // that is slightly higher that the minimum interval, and
798 // spread the blame across all applications with a request
799 // under that threshold.
800 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
801 for (UpdateRecord record : records) {
802 LocationRequest locationRequest = record.mRequest;
803 if (locationRequest.getInterval() <= thresholdInterval) {
804 worksource.add(record.mReceiver.mUid);
805 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700806 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
808 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700809
810 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
811 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 }
813
814 private class UpdateRecord {
815 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700816 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400818 Location mLastFixBroadcast;
819 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820
821 /**
822 * Note: must be constructed with lock held.
823 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700824 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700826 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828
829 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
830 if (records == null) {
831 records = new ArrayList<UpdateRecord>();
832 mRecordsByProvider.put(provider, records);
833 }
834 if (!records.contains(this)) {
835 records.add(this);
836 }
837 }
838
839 /**
840 * Method to be called when a record will no longer be used. Calling this multiple times
841 * must have the same effect as calling it once.
842 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700843 void disposeLocked(boolean removeReceiver) {
844 // remove from mRecordsByProvider
845 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
846 if (globalRecords != null) {
847 globalRecords.remove(this);
848 }
849
850 if (!removeReceiver) return; // the caller will handle the rest
851
852 // remove from Receiver#mUpdateRecords
853 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
854 if (receiverRecords != null) {
855 receiverRecords.remove(this.mProvider);
856
857 // and also remove the Receiver if it has no more update records
858 if (removeReceiver && receiverRecords.size() == 0) {
859 removeUpdatesLocked(mReceiver);
860 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400861 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 }
863
864 @Override
865 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700866 StringBuilder s = new StringBuilder();
867 s.append("UpdateRecord[");
868 s.append(mProvider);
869 s.append(' ').append(mReceiver.mPackageName).append('(');
870 s.append(mReceiver.mUid).append(')');
871 s.append(' ').append(mRequest);
872 s.append(']');
873 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 }
876
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700877 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400878 IBinder binder = listener.asBinder();
879 Receiver receiver = mReceivers.get(binder);
880 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700881 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400882 mReceivers.put(binder, receiver);
883
884 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700885 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400886 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800887 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400888 return null;
889 }
890 }
891 return receiver;
892 }
893
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700894 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400895 Receiver receiver = mReceivers.get(intent);
896 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700897 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400898 mReceivers.put(intent, receiver);
899 }
900 return receiver;
901 }
902
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700903 private String checkPermissionAndRequest(LocationRequest request) {
904 String perm = checkPermission();
905
906 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700907 switch (request.getQuality()) {
908 case LocationRequest.ACCURACY_FINE:
909 request.setQuality(LocationRequest.ACCURACY_BLOCK);
910 break;
911 case LocationRequest.POWER_HIGH:
912 request.setQuality(LocationRequest.POWER_LOW);
913 break;
914 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700915 // throttle
916 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
917 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
918 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700919 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
920 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
921 }
922 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700923 // make getFastestInterval() the minimum of interval and fastest interval
924 if (request.getFastestInterval() > request.getInterval()) {
925 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400926 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700927 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400928 }
929
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700930 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700931 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700932 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700933 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700934 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700935 String[] packages = mPackageManager.getPackagesForUid(uid);
936 if (packages == null) {
937 throw new SecurityException("invalid UID " + uid);
938 }
939 for (String pkg : packages) {
940 if (packageName.equals(pkg)) return;
941 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700942 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700943 }
944
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700945 private void checkPendingIntent(PendingIntent intent) {
946 if (intent == null) {
947 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700948 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700949 }
950
951 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
952 int pid, int uid, String packageName) {
953 if (intent == null && listener == null) {
954 throw new IllegalArgumentException("need eiter listener or intent");
955 } else if (intent != null && listener != null) {
956 throw new IllegalArgumentException("cannot register both listener and intent");
957 } else if (intent != null) {
958 checkPendingIntent(intent);
959 return getReceiver(intent, pid, uid, packageName);
960 } else {
961 return getReceiver(listener, pid, uid, packageName);
962 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700963 }
964
Nick Pellye0fd6932012-07-11 10:26:13 -0700965 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700966 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
967 PendingIntent intent, String packageName) {
968 if (request == null) request = DEFAULT_LOCATION_REQUEST;
969 checkPackageName(packageName);
970 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700972 final int pid = Binder.getCallingPid();
973 final int uid = Binder.getCallingUid();
974 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975
Nick Pelly2b7a0d02012-08-17 15:09:44 -0700976 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 long identity = Binder.clearCallingIdentity();
978 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700979 synchronized (mLock) {
980 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400981 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 } finally {
983 Binder.restoreCallingIdentity(identity);
984 }
985 }
986
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700987 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
988 int pid, int uid, String packageName) {
989 // Figure out the provider. Either its explicitly request (legacy use cases), or
990 // use the fused provider
991 if (request == null) request = DEFAULT_LOCATION_REQUEST;
992 String name = request.getProvider();
993 if (name == null) name = LocationManager.FUSED_PROVIDER;
994 LocationProviderInterface provider = mProvidersByName.get(name);
995 if (provider == null) {
996 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
997 }
998
999 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1000 name + " " + request + " from " + packageName + "(" + uid + ")");
1001
1002 UpdateRecord record = new UpdateRecord(name, request, receiver);
1003 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1004 if (oldRecord != null) {
1005 oldRecord.disposeLocked(false);
1006 }
1007
1008 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1009 if (isProviderEnabled) {
1010 applyRequirementsLocked(name);
1011 } else {
1012 // Notify the listener that updates are currently disabled
1013 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001014 }
1015 }
1016
Nick Pellye0fd6932012-07-11 10:26:13 -07001017 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001018 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1019 String packageName) {
1020 checkPackageName(packageName);
1021 checkPermission();
1022 final int pid = Binder.getCallingPid();
1023 final int uid = Binder.getCallingUid();
1024 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1025
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001026 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001027 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001029 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001030 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001032 } finally {
1033 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 }
1035 }
1036
1037 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001038 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1039
1040 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1041 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1042 synchronized (receiver) {
1043 if (receiver.mPendingBroadcasts > 0) {
1044 decrementPendingBroadcasts();
1045 receiver.mPendingBroadcasts = 0;
1046 }
1047 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 }
1049
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001050 // Record which providers were associated with this listener
1051 HashSet<String> providers = new HashSet<String>();
1052 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1053 if (oldRecords != null) {
1054 // Call dispose() on the obsolete update records.
1055 for (UpdateRecord record : oldRecords.values()) {
1056 record.disposeLocked(false);
1057 }
1058 // Accumulate providers
1059 providers.addAll(oldRecords.keySet());
1060 }
1061
1062 // update provider
1063 for (String provider : providers) {
1064 // If provider is already disabled, don't need to do anything
1065 if (!isAllowedBySettingsLocked(provider)) {
1066 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 }
1068
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001069 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 }
1071 }
1072
Nick Pellye0fd6932012-07-11 10:26:13 -07001073 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001074 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001075 if (D) Log.d(TAG, "getLastLocation: " + request);
1076 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1077 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001078 checkPackageName(packageName);
1079
1080 if (mBlacklist.isBlacklisted(packageName)) {
1081 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1082 packageName);
1083 return null;
1084 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001085
1086 synchronized (mLock) {
1087 // Figure out the provider. Either its explicitly request (deprecated API's),
1088 // or use the fused provider
1089 String name = request.getProvider();
1090 if (name == null) name = LocationManager.FUSED_PROVIDER;
1091 LocationProviderInterface provider = mProvidersByName.get(name);
1092 if (provider == null) return null;
1093
1094 if (!isAllowedBySettingsLocked(name)) return null;
1095
1096 Location location = mLastLocation.get(name);
1097 if (ACCESS_FINE_LOCATION.equals(perm)) {
1098 return location;
1099 } else {
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001100 return mLocationFudger.getOrCreate(location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001101 }
1102 }
1103 }
1104
1105 @Override
1106 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1107 String packageName) {
1108 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001109 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001110 checkPermissionAndRequest(request);
1111 checkPendingIntent(intent);
1112 checkPackageName(packageName);
1113
1114 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1115
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001116 // geo-fence manager uses the public location API, need to clear identity
1117 int uid = Binder.getCallingUid();
1118 long identity = Binder.clearCallingIdentity();
1119 try {
1120 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1121 } finally {
1122 Binder.restoreCallingIdentity(identity);
1123 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001124 }
1125
1126 @Override
1127 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001128 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001129 checkPendingIntent(intent);
1130 checkPackageName(packageName);
1131
1132 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1133
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001134 // geo-fence manager uses the public location API, need to clear identity
1135 long identity = Binder.clearCallingIdentity();
1136 try {
1137 mGeofenceManager.removeFence(geofence, intent);
1138 } finally {
1139 Binder.restoreCallingIdentity(identity);
1140 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001141 }
1142
1143
1144 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001146 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 return false;
1148 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001149 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 PackageManager.PERMISSION_GRANTED) {
1151 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1152 }
1153
1154 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001155 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001157 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 return false;
1159 }
1160 return true;
1161 }
1162
Nick Pellye0fd6932012-07-11 10:26:13 -07001163 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001165 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001166 try {
1167 mGpsStatusProvider.removeGpsStatusListener(listener);
1168 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001169 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001171 }
1172 }
1173
Nick Pellye0fd6932012-07-11 10:26:13 -07001174 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001176 if (provider == null) {
1177 // throw NullPointerException to remain compatible with previous implementation
1178 throw new NullPointerException();
1179 }
1180
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001181 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001183 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 != PackageManager.PERMISSION_GRANTED)) {
1185 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1186 }
1187
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001188 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001189 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001190 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001191
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001192 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
1194 }
1195
Nick Pellye0fd6932012-07-11 10:26:13 -07001196 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001197 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001198 if (Binder.getCallingUid() != Process.myUid()) {
1199 throw new SecurityException(
1200 "calling sendNiResponse from outside of the system is not allowed");
1201 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001202 try {
1203 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001204 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001205 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001206 return false;
1207 }
1208 }
1209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001211 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001212 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 * accessed by the caller
1214 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001215 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001216 public ProviderProperties getProviderProperties(String provider) {
1217 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001219 LocationProviderInterface p;
1220 synchronized (mLock) {
1221 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 }
1223
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001224 if (p == null) return null;
1225 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 }
1227
Nick Pellye0fd6932012-07-11 10:26:13 -07001228 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001230 checkPermission();
1231 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1232
1233 synchronized (mLock) {
1234 LocationProviderInterface p = mProvidersByName.get(provider);
1235 if (p == null) return false;
1236
1237 return isAllowedBySettingsLocked(provider);
1238 }
1239 }
1240
1241 private void checkCallerIsProvider() {
1242 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1243 == PackageManager.PERMISSION_GRANTED) {
1244 return;
1245 }
1246
1247 // Previously we only used the INSTALL_LOCATION_PROVIDER
1248 // check. But that is system or signature
1249 // protection level which is not flexible enough for
1250 // providers installed oustide the system image. So
1251 // also allow providers with a UID matching the
1252 // currently bound package name
1253
1254 int uid = Binder.getCallingUid();
1255
1256 if (mGeocodeProvider != null) {
1257 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1258 }
1259 for (LocationProviderProxy proxy : mProxyProviders) {
1260 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1261 }
1262 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1263 "or UID of a currently bound location provider");
1264 }
1265
1266 private boolean doesPackageHaveUid(int uid, String packageName) {
1267 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 return false;
1269 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001270 try {
1271 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1272 if (appInfo.uid != uid) {
1273 return false;
1274 }
1275 } catch (NameNotFoundException e) {
1276 return false;
1277 }
1278 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 }
1280
Nick Pellye0fd6932012-07-11 10:26:13 -07001281 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001282 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001283 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001284
Nick Pelly2eeeec22012-07-18 13:13:37 -07001285 if (!location.isComplete()) {
1286 Log.w(TAG, "Dropping incomplete location: " + location);
1287 return;
1288 }
1289
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001290 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1291 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001292 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001293 mLocationHandler.sendMessageAtFrontOfQueue(m);
1294 }
1295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296
1297 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1298 // Always broadcast the first update
1299 if (lastLoc == null) {
1300 return true;
1301 }
1302
Nick Pellyf1be6862012-05-15 10:53:42 -07001303 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001304 long minTime = record.mRequest.getFastestInterval();
Nick Pelly2eeeec22012-07-18 13:13:37 -07001305 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001306 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001307 return false;
1308 }
1309
1310 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001311 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 if (minDistance > 0.0) {
1313 if (loc.distanceTo(lastLoc) <= minDistance) {
1314 return false;
1315 }
1316 }
1317
1318 return true;
1319 }
1320
Mike Lockwooda4903f22010-02-17 06:42:23 -05001321 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001322 if (D) Log.d(TAG, "incoming location: " + location);
1323
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001325 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001326 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001327 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001329 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001330 if (p == null) return;
1331
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001332 // Add the coarse location as an extra
1333 Location coarse = mLocationFudger.getOrCreate(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001335 // Update last known locations
1336 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001337 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001338 lastLocation = new Location(provider);
1339 mLastLocation.put(provider, lastLocation);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001340 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001341 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 // Fetch latest status update time
1344 long newStatusUpdateTime = p.getStatusUpdateTime();
1345
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001346 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 Bundle extras = new Bundle();
1348 int status = p.getStatus(extras);
1349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001351 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001354 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001356 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001357
1358 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1359 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1360 receiver.mPackageName);
1361 continue;
1362 }
1363
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001364 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1365 location = lastLocation; // use fine location
1366 } else {
1367 location = coarse; // use coarse location
1368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001370 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001371 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1372 if (lastLoc == null) {
1373 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001374 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001375 } else {
1376 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001378 if (!receiver.callLocationChangedLocked(location)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001379 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001380 receiverDead = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 }
1382 }
1383
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001384 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1386 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1387
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001388 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001390 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001391 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001392 }
1393 }
1394
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001395 // track expired records
1396 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1397 if (deadUpdateRecords == null) {
1398 deadUpdateRecords = new ArrayList<UpdateRecord>();
1399 }
1400 deadUpdateRecords.add(r);
1401 }
1402 // track dead receivers
1403 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001404 if (deadReceivers == null) {
1405 deadReceivers = new ArrayList<Receiver>();
1406 }
1407 if (!deadReceivers.contains(receiver)) {
1408 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 }
1410 }
1411 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001412
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001413 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001415 for (Receiver receiver : deadReceivers) {
1416 removeUpdatesLocked(receiver);
1417 }
1418 }
1419 if (deadUpdateRecords != null) {
1420 for (UpdateRecord r : deadUpdateRecords) {
1421 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 }
1423 }
1424 }
1425
1426 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 @Override
1428 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001429 switch (msg.what) {
1430 case MSG_LOCATION_CHANGED:
1431 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1432 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 }
1434 }
1435 }
1436
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001437 private void handleLocationChanged(Location location, boolean passive) {
1438 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001439
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001440 if (!passive) {
1441 // notify passive provider of the new location
1442 mPassiveProvider.updateLocation(location);
1443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001445 synchronized (mLock) {
1446 if (isAllowedBySettingsLocked(provider)) {
1447 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001450 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451
Mike Lockwoode97ae402010-09-29 15:23:46 -04001452 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1453 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001454 public void onPackageDisappeared(String packageName, int reason) {
1455 // remove all receivers associated with this package name
1456 synchronized (mLock) {
1457 ArrayList<Receiver> deadReceivers = null;
1458
1459 for (Receiver receiver : mReceivers.values()) {
1460 if (receiver.mPackageName.equals(packageName)) {
1461 if (deadReceivers == null) {
1462 deadReceivers = new ArrayList<Receiver>();
1463 }
1464 deadReceivers.add(receiver);
1465 }
1466 }
1467
1468 // perform removal outside of mReceivers loop
1469 if (deadReceivers != null) {
1470 for (Receiver receiver : deadReceivers) {
1471 removeUpdatesLocked(receiver);
1472 }
1473 }
1474 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001475 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001476 };
1477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 // Wake locks
1479
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001480 private void incrementPendingBroadcasts() {
1481 synchronized (mWakeLock) {
1482 if (mPendingBroadcasts++ == 0) {
1483 try {
1484 mWakeLock.acquire();
1485 log("Acquired wakelock");
1486 } catch (Exception e) {
1487 // This is to catch a runtime exception thrown when we try to release an
1488 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001489 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001490 }
1491 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001492 }
1493 }
1494
1495 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001496 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001497 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001498 try {
1499 // Release wake lock
1500 if (mWakeLock.isHeld()) {
1501 mWakeLock.release();
1502 log("Released wakelock");
1503 } else {
1504 log("Can't release wakelock again!");
1505 }
1506 } catch (Exception e) {
1507 // This is to catch a runtime exception thrown when we try to release an
1508 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001509 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001510 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001511 }
1512 }
1513 }
1514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 // Geocoder
1516
Nick Pellye0fd6932012-07-11 10:26:13 -07001517 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001518 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001519 return mGeocodeProvider != null;
1520 }
1521
Nick Pellye0fd6932012-07-11 10:26:13 -07001522 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001524 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001525 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001526 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1527 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001529 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 }
1531
Mike Lockwooda55c3212009-04-15 11:10:11 -04001532
Nick Pellye0fd6932012-07-11 10:26:13 -07001533 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001535 double lowerLeftLatitude, double lowerLeftLongitude,
1536 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001537 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001538
1539 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001540 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1541 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1542 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001544 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 }
1546
1547 // Mock Providers
1548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 private void checkMockPermissionsSafe() {
1550 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1551 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1552 if (!allowMocks) {
1553 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1554 }
1555
1556 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1557 PackageManager.PERMISSION_GRANTED) {
1558 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 }
1561
Nick Pellye0fd6932012-07-11 10:26:13 -07001562 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001563 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 checkMockPermissionsSafe();
1565
Mike Lockwooda4903f22010-02-17 06:42:23 -05001566 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1567 throw new IllegalArgumentException("Cannot mock the passive location provider");
1568 }
1569
Mike Lockwood86328a92009-10-23 08:38:25 -04001570 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001571 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001572 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001573 // remove the real provider if we are replacing GPS or network provider
1574 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001575 || LocationManager.NETWORK_PROVIDER.equals(name)
1576 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001577 LocationProviderInterface p = mProvidersByName.get(name);
1578 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001579 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001580 }
1581 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001582 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1584 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001585 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001586 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001587 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 updateProvidersLocked();
1589 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001590 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 }
1592
Nick Pellye0fd6932012-07-11 10:26:13 -07001593 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 public void removeTestProvider(String provider) {
1595 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001596 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001597 MockProvider mockProvider = mMockProviders.get(provider);
1598 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1600 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001601 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001602 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001603 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001604
1605 // reinstate real provider if available
1606 LocationProviderInterface realProvider = mRealProviders.get(provider);
1607 if (realProvider != null) {
1608 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001609 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001610 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001612 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 }
1614 }
1615
Nick Pellye0fd6932012-07-11 10:26:13 -07001616 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 public void setTestProviderLocation(String provider, Location loc) {
1618 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001619 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001620 MockProvider mockProvider = mMockProviders.get(provider);
1621 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1623 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001624 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1625 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001626 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001627 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 }
1629 }
1630
Nick Pellye0fd6932012-07-11 10:26:13 -07001631 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 public void clearTestProviderLocation(String provider) {
1633 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001634 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001635 MockProvider mockProvider = mMockProviders.get(provider);
1636 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001637 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1638 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001639 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 }
1641 }
1642
Nick Pellye0fd6932012-07-11 10:26:13 -07001643 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 public void setTestProviderEnabled(String provider, boolean enabled) {
1645 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001646 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001647 MockProvider mockProvider = mMockProviders.get(provider);
1648 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001649 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1650 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001651 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001653 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 mEnabledProviders.add(provider);
1655 mDisabledProviders.remove(provider);
1656 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001657 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 mEnabledProviders.remove(provider);
1659 mDisabledProviders.add(provider);
1660 }
1661 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001662 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 }
1664 }
1665
Nick Pellye0fd6932012-07-11 10:26:13 -07001666 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 public void clearTestProviderEnabled(String provider) {
1668 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001669 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001670 MockProvider mockProvider = mMockProviders.get(provider);
1671 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1673 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001674 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 mEnabledProviders.remove(provider);
1676 mDisabledProviders.remove(provider);
1677 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001678 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 }
1680 }
1681
Nick Pellye0fd6932012-07-11 10:26:13 -07001682 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1684 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001685 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001686 MockProvider mockProvider = mMockProviders.get(provider);
1687 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1689 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001690 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 }
1692 }
1693
Nick Pellye0fd6932012-07-11 10:26:13 -07001694 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 public void clearTestProviderStatus(String provider) {
1696 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001697 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001698 MockProvider mockProvider = mMockProviders.get(provider);
1699 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1701 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001702 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 }
1704 }
1705
1706 private void log(String log) {
1707 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001708 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 }
1710 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001711
1712 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1714 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1715 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001716 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 + Binder.getCallingPid()
1718 + ", uid=" + Binder.getCallingUid());
1719 return;
1720 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001721
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001722 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001725 for (Receiver receiver : mReceivers.values()) {
1726 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001729 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1730 pw.println(" " + entry.getKey() + ":");
1731 for (UpdateRecord record : entry.getValue()) {
1732 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 }
1734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001736 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1737 String provider = entry.getKey();
1738 Location location = entry.getValue();
1739 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001741
Nick Pellye0fd6932012-07-11 10:26:13 -07001742 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 if (mEnabledProviders.size() > 0) {
1745 pw.println(" Enabled Providers:");
1746 for (String i : mEnabledProviders) {
1747 pw.println(" " + i);
1748 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001749
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 }
1751 if (mDisabledProviders.size() > 0) {
1752 pw.println(" Disabled Providers:");
1753 for (String i : mDisabledProviders) {
1754 pw.println(" " + i);
1755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001757 pw.append(" ");
1758 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 if (mMockProviders.size() > 0) {
1760 pw.println(" Mock Providers:");
1761 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001762 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 }
1764 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001765
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001766 pw.append(" fudger: ");
1767 mLocationFudger.dump(fd, pw, args);
1768
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001769 if (args.length > 0 && "short".equals(args[0])) {
1770 return;
1771 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001772 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001773 pw.print(provider.getName() + " Internal State");
1774 if (provider instanceof LocationProviderProxy) {
1775 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1776 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001777 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001778 pw.println(":");
1779 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001780 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 }
1782 }
1783}