blob: ae95c4c00882ca5e400bb1a78e5da9f9a2734d00 [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;
Victoria Lease38389b62012-09-30 11:44:22 -070020import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070024import 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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070031import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050032import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070033import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040035import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.location.ILocationListener;
37import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040038import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.Location;
40import android.location.LocationManager;
41import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070042import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.os.Binder;
44import android.os.Bundle;
45import android.os.Handler;
46import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070047import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.Message;
49import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070050import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070052import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070053import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070054import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080057import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
Mike Lockwoode97ae402010-09-29 15:23:46 -040059import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070060import com.android.internal.location.ProviderProperties;
61import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040062import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070063import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040064import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070065import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070066import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040067import com.android.server.location.LocationProviderInterface;
68import com.android.server.location.LocationProviderProxy;
69import com.android.server.location.MockProvider;
70import com.android.server.location.PassiveProvider;
71
72import java.io.FileDescriptor;
73import java.io.PrintWriter;
74import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070075import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040076import java.util.HashMap;
77import java.util.HashSet;
78import java.util.List;
79import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040080import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081
82/**
83 * The service class that manages LocationProviders and issues location
84 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 */
Brian Muramatsubb95cb92012-08-29 10:43:21 -070086public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070088 public static final boolean D = false;
89
90 private static final String WAKELOCK_KEY = TAG;
91 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 private static final String ACCESS_FINE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070094 android.Manifest.permission.ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 private static final String ACCESS_COARSE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070096 android.Manifest.permission.ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070098 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700100 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400101 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700102 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
103
104 private static final String NETWORK_LOCATION_SERVICE_ACTION =
105 "com.android.location.service.v2.NetworkLocationProvider";
106 private static final String FUSED_LOCATION_SERVICE_ACTION =
107 "com.android.location.service.FusedLocationProvider";
108
109 private static final int MSG_LOCATION_CHANGED = 1;
110
Nick Pellyf1be6862012-05-15 10:53:42 -0700111 // Location Providers may sometimes deliver location updates
112 // slightly faster that requested - provide grace period so
113 // we don't unnecessarily filter events that are otherwise on
114 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700115 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700116
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700117 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
118
119 private final Context mContext;
120
121 // used internally for synchronization
122 private final Object mLock = new Object();
123
124 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700125 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700126 private GeofenceManager mGeofenceManager;
127 private PowerManager.WakeLock mWakeLock;
128 private PackageManager mPackageManager;
129 private GeocoderProxy mGeocodeProvider;
130 private IGpsStatusProvider mGpsStatusProvider;
131 private INetInitiatedListener mNetInitiatedListener;
132 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700133 private PassiveProvider mPassiveProvider; // track passive provider for special cases
134 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700135
136 // --- fields below are protected by mWakeLock ---
137 private int mPendingBroadcasts;
138
139 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 // Set of providers that are explicitly enabled
141 private final Set<String> mEnabledProviders = new HashSet<String>();
142
143 // Set of providers that are explicitly disabled
144 private final Set<String> mDisabledProviders = new HashSet<String>();
145
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700146 // Mock (test) providers
147 private final HashMap<String, MockProvider> mMockProviders =
148 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700150 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400151 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700153 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500154 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400156
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700157 // real providers, saved here when mocked out
158 private final HashMap<String, LocationProviderInterface> mRealProviders =
159 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700161 // mapping from provider name to provider
162 private final HashMap<String, LocationProviderInterface> mProvidersByName =
163 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700165 // mapping from provider name to all its UpdateRecords
166 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
167 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // mapping from provider name to last known location
170 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172 // all providers that operate over proxy, for authorizing incoming location
173 private final ArrayList<LocationProviderProxy> mProxyProviders =
174 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175
Victoria Lease38389b62012-09-30 11:44:22 -0700176 // current active user on the device - other users are denied location data
177 private int mCurrentUserId = UserHandle.USER_OWNER;
178
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700179 public LocationManagerService(Context context) {
180 super();
181 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800182
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 if (D) Log.d(TAG, "Constructed");
184
185 // most startup is deferred until systemReady()
186 }
187
188 public void systemReady() {
189 Thread thread = new Thread(null, this, THREAD_NAME);
190 thread.start();
191 }
192
193 @Override
194 public void run() {
195 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
196 Looper.prepare();
197 mLocationHandler = new LocationWorkerHandler();
198 init();
199 Looper.loop();
200 }
201
202 private void init() {
203 if (D) Log.d(TAG, "init()");
204
205 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
206 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
207 mPackageManager = mContext.getPackageManager();
208
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700209 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
210 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700211 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700212
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700213 synchronized (mLock) {
214 loadProvidersLocked();
215 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700216
Nick Pelly4035f5a2012-08-17 14:43:49 -0700217 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700218
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700219 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700220 mContext.getContentResolver().registerContentObserver(
221 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
222 new ContentObserver(mLocationHandler) {
223 @Override
224 public void onChange(boolean selfChange) {
225 synchronized (mLock) {
226 updateProvidersLocked();
227 }
228 }
229 });
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700230 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700231
Victoria Lease38389b62012-09-30 11:44:22 -0700232 // listen for user change
233 IntentFilter intentFilter = new IntentFilter();
234 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
235
236 mContext.registerReceiverAsUser(new BroadcastReceiver() {
237 @Override
238 public void onReceive(Context context, Intent intent) {
239 String action = intent.getAction();
240 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
241 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
242 }
243 }
244 }, UserHandle.ALL, intentFilter, null, null);
245
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700246 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700247 }
248
249 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700250 // create a passive location provider, which is always enabled
251 PassiveProvider passiveProvider = new PassiveProvider(this);
252 addProviderLocked(passiveProvider);
253 mEnabledProviders.add(passiveProvider.getName());
254 mPassiveProvider = passiveProvider;
255
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700256 if (GpsLocationProvider.isSupported()) {
257 // Create a gps location provider
258 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
259 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
260 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
261 addProviderLocked(gpsProvider);
262 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
263 }
264
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700265 /*
266 Load package name(s) containing location provider support.
267 These packages can contain services implementing location providers:
268 Geocoder Provider, Network Location Provider, and
269 Fused Location Provider. They will each be searched for
270 service components implementing these providers.
271 The location framework also has support for installation
272 of new location providers at run-time. The new package does not
273 have to be explicitly listed here, however it must have a signature
274 that matches the signature of at least one package on this list.
275 */
276 Resources resources = mContext.getResources();
277 ArrayList<String> providerPackageNames = new ArrayList<String>();
278 String[] pkgs1 = resources.getStringArray(
279 com.android.internal.R.array.config_locationProviderPackageNames);
280 String[] pkgs2 = resources.getStringArray(
281 com.android.internal.R.array.config_overlay_locationProviderPackageNames);
282 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
283 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
284 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
285 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
286
287 // bind to network provider
288 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
289 mContext,
290 LocationManager.NETWORK_PROVIDER,
291 NETWORK_LOCATION_SERVICE_ACTION,
292 providerPackageNames, mLocationHandler);
293 if (networkProvider != null) {
294 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
295 mProxyProviders.add(networkProvider);
296 addProviderLocked(networkProvider);
297 } else {
298 Slog.w(TAG, "no network location provider found");
299 }
300
301 // bind to fused provider
302 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
303 mContext,
304 LocationManager.FUSED_PROVIDER,
305 FUSED_LOCATION_SERVICE_ACTION,
306 providerPackageNames, mLocationHandler);
307 if (fusedLocationProvider != null) {
308 addProviderLocked(fusedLocationProvider);
309 mProxyProviders.add(fusedLocationProvider);
310 mEnabledProviders.add(fusedLocationProvider.getName());
311 } else {
312 Slog.e(TAG, "no fused location provider found",
313 new IllegalStateException("Location service needs a fused location provider"));
314 }
315
316 // bind to geocoder provider
317 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
318 if (mGeocodeProvider == null) {
319 Slog.e(TAG, "no geocoder provider found");
320 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700321 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700324 * Called when the device's active user changes.
325 * @param userId the new active user's UserId
326 */
327 private void switchUser(int userId) {
328 //Log.d("LocationManagerService", "switchUser(" + mCurrentUserId + " -> " + userId + ")"); // TODO: remove this
329 synchronized (mLock) {
330 // TODO: inform previous user's Receivers that they will no longer receive updates
331 mCurrentUserId = userId;
332 // TODO: inform new user's Receivers that they are back on the update train
333 }
334 }
335
336 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
338 * location updates.
339 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700340 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700341 final int mUid; // uid of receiver
342 final int mPid; // pid of receiver
343 final String mPackageName; // package name of receiver
344 final String mPermission; // best permission that receiver has
345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 final ILocationListener mListener;
347 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700349
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400350 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700351
Mike Lockwood48f17512009-04-23 09:12:08 -0700352 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700354 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
355 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700358 if (listener != null) {
359 mKey = listener.asBinder();
360 } else {
361 mKey = intent;
362 }
363 mPermission = checkPermission();
364 mUid = uid;
365 mPid = pid;
366 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 }
368
369 @Override
370 public boolean equals(Object otherObj) {
371 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700372 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 }
374 return false;
375 }
376
377 @Override
378 public int hashCode() {
379 return mKey.hashCode();
380 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 @Override
383 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700384 StringBuilder s = new StringBuilder();
385 s.append("Reciever[");
386 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700388 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700390 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700392 for (String p : mUpdateRecords.keySet()) {
393 s.append(" ").append(mUpdateRecords.get(p).toString());
394 }
395 s.append("]");
396 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 }
398
399 public boolean isListener() {
400 return mListener != null;
401 }
402
403 public boolean isPendingIntent() {
404 return mPendingIntent != null;
405 }
406
407 public ILocationListener getListener() {
408 if (mListener != null) {
409 return mListener;
410 }
411 throw new IllegalStateException("Request for non-existent listener");
412 }
413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
415 if (mListener != null) {
416 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700417 synchronized (this) {
418 // synchronize to ensure incrementPendingBroadcastsLocked()
419 // is called before decrementPendingBroadcasts()
420 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700421 // call this after broadcasting so we do not increment
422 // if we throw an exeption.
423 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700424 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 } catch (RemoteException e) {
426 return false;
427 }
428 } else {
429 Intent statusChanged = new Intent();
430 statusChanged.putExtras(extras);
431 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
432 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700433 synchronized (this) {
434 // synchronize to ensure incrementPendingBroadcastsLocked()
435 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700436 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700437 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700438 // call this after broadcasting so we do not increment
439 // if we throw an exeption.
440 incrementPendingBroadcastsLocked();
441 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 } catch (PendingIntent.CanceledException e) {
443 return false;
444 }
445 }
446 return true;
447 }
448
449 public boolean callLocationChangedLocked(Location location) {
450 if (mListener != null) {
451 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700452 synchronized (this) {
453 // synchronize to ensure incrementPendingBroadcastsLocked()
454 // is called before decrementPendingBroadcasts()
455 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700456 // call this after broadcasting so we do not increment
457 // if we throw an exeption.
458 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 } catch (RemoteException e) {
461 return false;
462 }
463 } else {
464 Intent locationChanged = new Intent();
465 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
466 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700467 synchronized (this) {
468 // synchronize to ensure incrementPendingBroadcastsLocked()
469 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700470 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700471 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700472 // call this after broadcasting so we do not increment
473 // if we throw an exeption.
474 incrementPendingBroadcastsLocked();
475 }
476 } catch (PendingIntent.CanceledException e) {
477 return false;
478 }
479 }
480 return true;
481 }
482
483 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
484 if (mListener != null) {
485 try {
486 synchronized (this) {
487 // synchronize to ensure incrementPendingBroadcastsLocked()
488 // is called before decrementPendingBroadcasts()
489 if (enabled) {
490 mListener.onProviderEnabled(provider);
491 } else {
492 mListener.onProviderDisabled(provider);
493 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700494 // call this after broadcasting so we do not increment
495 // if we throw an exeption.
496 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700497 }
498 } catch (RemoteException e) {
499 return false;
500 }
501 } else {
502 Intent providerIntent = new Intent();
503 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
504 try {
505 synchronized (this) {
506 // synchronize to ensure incrementPendingBroadcastsLocked()
507 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700508 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700509 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700510 // call this after broadcasting so we do not increment
511 // if we throw an exeption.
512 incrementPendingBroadcastsLocked();
513 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 } catch (PendingIntent.CanceledException e) {
515 return false;
516 }
517 }
518 return true;
519 }
520
Nick Pellyf1be6862012-05-15 10:53:42 -0700521 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700523 if (D) Log.d(TAG, "Location listener died");
524
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400525 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 removeUpdatesLocked(this);
527 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700528 synchronized (this) {
529 if (mPendingBroadcasts > 0) {
530 LocationManagerService.this.decrementPendingBroadcasts();
531 mPendingBroadcasts = 0;
532 }
533 }
534 }
535
Nick Pellye0fd6932012-07-11 10:26:13 -0700536 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700537 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
538 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400539 synchronized (this) {
540 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700541 }
542 }
543
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400544 // this must be called while synchronized by caller in a synchronized block
545 // containing the sending of the broadcaset
546 private void incrementPendingBroadcastsLocked() {
547 if (mPendingBroadcasts++ == 0) {
548 LocationManagerService.this.incrementPendingBroadcasts();
549 }
550 }
551
552 private void decrementPendingBroadcastsLocked() {
553 if (--mPendingBroadcasts == 0) {
554 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700555 }
556 }
557 }
558
Nick Pellye0fd6932012-07-11 10:26:13 -0700559 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700560 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400561 //Do not use getReceiver here as that will add the ILocationListener to
562 //the receiver list if it is not found. If it is not found then the
563 //LocationListener was removed when it had a pending broadcast and should
564 //not be added back.
565 IBinder binder = listener.asBinder();
566 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700567 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400568 synchronized (receiver) {
569 // so wakelock calls will succeed
570 long identity = Binder.clearCallingIdentity();
571 receiver.decrementPendingBroadcastsLocked();
572 Binder.restoreCallingIdentity(identity);
573 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 }
575 }
576
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700577 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400578 mProviders.add(provider);
579 mProvidersByName.put(provider.getName(), provider);
580 }
581
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700582 private void removeProviderLocked(LocationProviderInterface provider) {
583 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400584 mProviders.remove(provider);
585 mProvidersByName.remove(provider.getName());
586 }
587
Mike Lockwood3d12b512009-04-21 23:25:35 -0700588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 private boolean isAllowedBySettingsLocked(String provider) {
590 if (mEnabledProviders.contains(provider)) {
591 return true;
592 }
593 if (mDisabledProviders.contains(provider)) {
594 return false;
595 }
596 // Use system settings
597 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598
Brad Larson8eb3ea62009-12-29 11:47:55 -0600599 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 }
601
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700602 /**
603 * Throw SecurityException if caller has neither COARSE or FINE.
604 * Otherwise, return the best permission.
605 */
606 private String checkPermission() {
607 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
608 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700609 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700610 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
611 PackageManager.PERMISSION_GRANTED) {
612 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700614
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700615 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
Victoria Lease4fab68b2012-09-13 13:20:59 -0700616 " ACCESS_FINE_LOCATION permission");
617 }
618
619 /**
620 * Throw SecurityException if caller lacks permission to use Geofences.
621 */
622 private void checkGeofencePermission() {
623 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
624 PackageManager.PERMISSION_GRANTED) {
625 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
626 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 }
628
Victoria Lease8dbb6342012-09-21 16:55:53 -0700629 private boolean isAllowedProviderSafe(String provider) {
630 if (LocationManager.GPS_PROVIDER.equals(provider) ||
631 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
632 // gps and passive providers require FINE permission
633 return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
634 == PackageManager.PERMISSION_GRANTED;
635 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
636 LocationManager.FUSED_PROVIDER.equals(provider)) {
637 // network and fused providers are ok with COARSE or FINE
638 return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
639 == PackageManager.PERMISSION_GRANTED) ||
640 (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
641 == PackageManager.PERMISSION_GRANTED);
642 }
643 return false;
644 }
645
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700646 /**
647 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700648 * fused, also including ones that are not permitted to
649 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700650 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700651 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700653 ArrayList<String> out;
654 synchronized (mLock) {
655 out = new ArrayList<String>(mProviders.size());
656 for (LocationProviderInterface provider : mProviders) {
657 String name = provider.getName();
658 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700659 continue;
660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 out.add(name);
662 }
663 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700664
665 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 return out;
667 }
668
Mike Lockwood03ca2162010-04-01 08:10:09 -0700669 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700670 * Return all providers by name, that match criteria and are optionally
671 * enabled.
672 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700673 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700674 @Override
675 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700676 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700677 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700678 out = new ArrayList<String>(mProviders.size());
679 for (LocationProviderInterface provider : mProviders) {
680 String name = provider.getName();
681 if (LocationManager.FUSED_PROVIDER.equals(name)) {
682 continue;
683 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700684 if (isAllowedProviderSafe(name)) {
685 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
686 continue;
687 }
688 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
689 name, provider.getProperties(), criteria)) {
690 continue;
691 }
692 out.add(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700693 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700694 }
695 }
696
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700697 if (D) Log.d(TAG, "getProviders()=" + out);
698 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700699 }
700
701 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700702 * Return the name of the best provider given a Criteria object.
703 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700704 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700705 * has been deprecated as well. So this method now uses
706 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700707 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700708 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700709 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700710 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700711
712 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700713 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700714 result = pickBest(providers);
715 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
716 return result;
717 }
718 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700719 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700720 result = pickBest(providers);
721 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
722 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700723 }
724
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700725 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700726 return null;
727 }
728
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700729 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700730 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700731 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700732 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
733 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700734 } else {
735 return providers.get(0);
736 }
737 }
738
Nick Pellye0fd6932012-07-11 10:26:13 -0700739 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700740 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700741 checkPermission();
742
Mike Lockwood03ca2162010-04-01 08:10:09 -0700743 LocationProviderInterface p = mProvidersByName.get(provider);
744 if (p == null) {
745 throw new IllegalArgumentException("provider=" + provider);
746 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700747
748 boolean result = LocationProvider.propertiesMeetCriteria(
749 p.getName(), p.getProperties(), criteria);
750 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
751 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700752 }
753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700755 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400756 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500757 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 boolean isEnabled = p.isEnabled();
759 String name = p.getName();
760 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 if (isEnabled && !shouldBeEnabled) {
762 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700763 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 } else if (!isEnabled && shouldBeEnabled) {
765 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700766 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700768 }
769 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700770 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
771 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 }
773 }
774
775 private void updateProviderListenersLocked(String provider, boolean enabled) {
776 int listeners = 0;
777
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500778 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700779 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780
781 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
784 if (records != null) {
785 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700786 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 UpdateRecord record = records.get(i);
788 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700789 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
790 if (deadReceivers == null) {
791 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 }
Simon Schoar46866572009-06-10 21:12:10 +0200793 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 }
795 listeners++;
796 }
797 }
798
799 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700800 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 removeUpdatesLocked(deadReceivers.get(i));
802 }
803 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 if (enabled) {
806 p.enable();
807 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700808 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 }
810 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 }
814
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700815 private void applyRequirementsLocked(String provider) {
816 LocationProviderInterface p = mProvidersByName.get(provider);
817 if (p == null) return;
818
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700820 WorkSource worksource = new WorkSource();
821 ProviderRequest providerRequest = new ProviderRequest();
822
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700824 for (UpdateRecord record : records) {
825 LocationRequest locationRequest = record.mRequest;
826
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700827 providerRequest.locationRequests.add(locationRequest);
828 if (locationRequest.getInterval() < providerRequest.interval) {
829 providerRequest.reportLocation = true;
830 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700831 }
832 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700833
834 if (providerRequest.reportLocation) {
835 // calculate who to blame for power
836 // This is somewhat arbitrary. We pick a threshold interval
837 // that is slightly higher that the minimum interval, and
838 // spread the blame across all applications with a request
839 // under that threshold.
840 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
841 for (UpdateRecord record : records) {
842 LocationRequest locationRequest = record.mRequest;
843 if (locationRequest.getInterval() <= thresholdInterval) {
844 worksource.add(record.mReceiver.mUid);
845 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700846 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 }
848 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700849
850 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
851 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 }
853
854 private class UpdateRecord {
855 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700856 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400858 Location mLastFixBroadcast;
859 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860
861 /**
862 * Note: must be constructed with lock held.
863 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700864 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700866 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868
869 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
870 if (records == null) {
871 records = new ArrayList<UpdateRecord>();
872 mRecordsByProvider.put(provider, records);
873 }
874 if (!records.contains(this)) {
875 records.add(this);
876 }
877 }
878
879 /**
880 * Method to be called when a record will no longer be used. Calling this multiple times
881 * must have the same effect as calling it once.
882 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700883 void disposeLocked(boolean removeReceiver) {
884 // remove from mRecordsByProvider
885 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
886 if (globalRecords != null) {
887 globalRecords.remove(this);
888 }
889
890 if (!removeReceiver) return; // the caller will handle the rest
891
892 // remove from Receiver#mUpdateRecords
893 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
894 if (receiverRecords != null) {
895 receiverRecords.remove(this.mProvider);
896
897 // and also remove the Receiver if it has no more update records
898 if (removeReceiver && receiverRecords.size() == 0) {
899 removeUpdatesLocked(mReceiver);
900 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 }
903
904 @Override
905 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700906 StringBuilder s = new StringBuilder();
907 s.append("UpdateRecord[");
908 s.append(mProvider);
909 s.append(' ').append(mReceiver.mPackageName).append('(');
910 s.append(mReceiver.mUid).append(')');
911 s.append(' ').append(mRequest);
912 s.append(']');
913 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 }
916
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700917 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400918 IBinder binder = listener.asBinder();
919 Receiver receiver = mReceivers.get(binder);
920 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700921 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400922 mReceivers.put(binder, receiver);
923
924 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700925 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400926 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800927 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400928 return null;
929 }
930 }
931 return receiver;
932 }
933
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700934 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400935 Receiver receiver = mReceivers.get(intent);
936 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700937 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400938 mReceivers.put(intent, receiver);
939 }
940 return receiver;
941 }
942
Victoria Lease09016ab2012-09-16 12:33:15 -0700943 private boolean isProviderAllowedByCoarsePermission(String provider) {
944 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
945 return true;
946 }
947 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
948 return true;
949 }
950 if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
951 return true;
952 }
953 return false;
954 }
955
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700956 private String checkPermissionAndRequest(LocationRequest request) {
957 String perm = checkPermission();
958
959 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Victoria Lease09016ab2012-09-16 12:33:15 -0700960 if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
961 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
962 }
963 switch (request.getQuality()) {
964 case LocationRequest.ACCURACY_FINE:
965 request.setQuality(LocationRequest.ACCURACY_BLOCK);
966 break;
967 case LocationRequest.POWER_HIGH:
968 request.setQuality(LocationRequest.POWER_LOW);
969 break;
970 }
971 // throttle
972 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
973 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
974 }
975 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
976 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
977 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700978 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700979 // make getFastestInterval() the minimum of interval and fastest interval
980 if (request.getFastestInterval() > request.getInterval()) {
981 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400982 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700983 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400984 }
985
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700986 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700987 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700988 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700989 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700990 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700991 String[] packages = mPackageManager.getPackagesForUid(uid);
992 if (packages == null) {
993 throw new SecurityException("invalid UID " + uid);
994 }
995 for (String pkg : packages) {
996 if (packageName.equals(pkg)) return;
997 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700998 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700999 }
1000
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001001 private void checkPendingIntent(PendingIntent intent) {
1002 if (intent == null) {
1003 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001004 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001005 }
1006
1007 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1008 int pid, int uid, String packageName) {
1009 if (intent == null && listener == null) {
1010 throw new IllegalArgumentException("need eiter listener or intent");
1011 } else if (intent != null && listener != null) {
1012 throw new IllegalArgumentException("cannot register both listener and intent");
1013 } else if (intent != null) {
1014 checkPendingIntent(intent);
1015 return getReceiver(intent, pid, uid, packageName);
1016 } else {
1017 return getReceiver(listener, pid, uid, packageName);
1018 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001019 }
1020
Nick Pellye0fd6932012-07-11 10:26:13 -07001021 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001022 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1023 PendingIntent intent, String packageName) {
1024 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1025 checkPackageName(packageName);
1026 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001028 final int pid = Binder.getCallingPid();
1029 final int uid = Binder.getCallingUid();
1030 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001032 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 long identity = Binder.clearCallingIdentity();
1034 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001035 synchronized (mLock) {
1036 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001037 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 } finally {
1039 Binder.restoreCallingIdentity(identity);
1040 }
1041 }
1042
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001043 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1044 int pid, int uid, String packageName) {
1045 // Figure out the provider. Either its explicitly request (legacy use cases), or
1046 // use the fused provider
1047 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1048 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001049 if (name == null) {
1050 throw new IllegalArgumentException("provider name must not be null");
1051 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001052 LocationProviderInterface provider = mProvidersByName.get(name);
1053 if (provider == null) {
1054 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1055 }
1056
1057 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1058 name + " " + request + " from " + packageName + "(" + uid + ")");
1059
1060 UpdateRecord record = new UpdateRecord(name, request, receiver);
1061 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1062 if (oldRecord != null) {
1063 oldRecord.disposeLocked(false);
1064 }
1065
1066 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1067 if (isProviderEnabled) {
1068 applyRequirementsLocked(name);
1069 } else {
1070 // Notify the listener that updates are currently disabled
1071 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 }
1073 }
1074
Nick Pellye0fd6932012-07-11 10:26:13 -07001075 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001076 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1077 String packageName) {
1078 checkPackageName(packageName);
1079 checkPermission();
1080 final int pid = Binder.getCallingPid();
1081 final int uid = Binder.getCallingUid();
1082 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1083
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001084 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001085 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001087 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001088 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001090 } finally {
1091 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 }
1093 }
1094
1095 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001096 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1097
1098 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1099 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1100 synchronized (receiver) {
1101 if (receiver.mPendingBroadcasts > 0) {
1102 decrementPendingBroadcasts();
1103 receiver.mPendingBroadcasts = 0;
1104 }
1105 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 }
1107
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001108 // Record which providers were associated with this listener
1109 HashSet<String> providers = new HashSet<String>();
1110 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1111 if (oldRecords != null) {
1112 // Call dispose() on the obsolete update records.
1113 for (UpdateRecord record : oldRecords.values()) {
1114 record.disposeLocked(false);
1115 }
1116 // Accumulate providers
1117 providers.addAll(oldRecords.keySet());
1118 }
1119
1120 // update provider
1121 for (String provider : providers) {
1122 // If provider is already disabled, don't need to do anything
1123 if (!isAllowedBySettingsLocked(provider)) {
1124 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 }
1126
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001127 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 }
1129 }
1130
Nick Pellye0fd6932012-07-11 10:26:13 -07001131 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001132 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001133 if (D) Log.d(TAG, "getLastLocation: " + request);
1134 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1135 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001136 checkPackageName(packageName);
1137
1138 if (mBlacklist.isBlacklisted(packageName)) {
1139 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1140 packageName);
1141 return null;
1142 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001143
1144 synchronized (mLock) {
1145 // Figure out the provider. Either its explicitly request (deprecated API's),
1146 // or use the fused provider
1147 String name = request.getProvider();
1148 if (name == null) name = LocationManager.FUSED_PROVIDER;
1149 LocationProviderInterface provider = mProvidersByName.get(name);
1150 if (provider == null) return null;
1151
1152 if (!isAllowedBySettingsLocked(name)) return null;
1153
1154 Location location = mLastLocation.get(name);
Victoria Lease09016ab2012-09-16 12:33:15 -07001155 if (location == null) {
1156 return null;
1157 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001158 if (ACCESS_FINE_LOCATION.equals(perm)) {
1159 return location;
1160 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001161 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1162 if (noGPSLocation != null) {
1163 return mLocationFudger.getOrCreate(noGPSLocation);
1164 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001165 }
1166 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001167 return null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001168 }
1169
1170 @Override
1171 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1172 String packageName) {
1173 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001174 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001175 checkPermissionAndRequest(request);
1176 checkPendingIntent(intent);
1177 checkPackageName(packageName);
1178
1179 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1180
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001181 // geo-fence manager uses the public location API, need to clear identity
1182 int uid = Binder.getCallingUid();
1183 long identity = Binder.clearCallingIdentity();
1184 try {
1185 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1186 } finally {
1187 Binder.restoreCallingIdentity(identity);
1188 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001189 }
1190
1191 @Override
1192 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001193 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001194 checkPendingIntent(intent);
1195 checkPackageName(packageName);
1196
1197 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1198
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001199 // geo-fence manager uses the public location API, need to clear identity
1200 long identity = Binder.clearCallingIdentity();
1201 try {
1202 mGeofenceManager.removeFence(geofence, intent);
1203 } finally {
1204 Binder.restoreCallingIdentity(identity);
1205 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001206 }
1207
1208
1209 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001211 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 return false;
1213 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001214 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 PackageManager.PERMISSION_GRANTED) {
1216 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1217 }
1218
1219 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001220 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001222 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 return false;
1224 }
1225 return true;
1226 }
1227
Nick Pellye0fd6932012-07-11 10:26:13 -07001228 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001230 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001231 try {
1232 mGpsStatusProvider.removeGpsStatusListener(listener);
1233 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001234 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001235 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001236 }
1237 }
1238
Nick Pellye0fd6932012-07-11 10:26:13 -07001239 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001241 if (provider == null) {
1242 // throw NullPointerException to remain compatible with previous implementation
1243 throw new NullPointerException();
1244 }
1245
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001246 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001248 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 != PackageManager.PERMISSION_GRANTED)) {
1250 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1251 }
1252
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001253 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001254 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001255 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001256
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001257 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 }
1259 }
1260
Nick Pellye0fd6932012-07-11 10:26:13 -07001261 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001262 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001263 if (Binder.getCallingUid() != Process.myUid()) {
1264 throw new SecurityException(
1265 "calling sendNiResponse from outside of the system is not allowed");
1266 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001267 try {
1268 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001269 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001270 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001271 return false;
1272 }
1273 }
1274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001276 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001277 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 * accessed by the caller
1279 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001280 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001281 public ProviderProperties getProviderProperties(String provider) {
1282 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 LocationProviderInterface p;
1285 synchronized (mLock) {
1286 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 }
1288
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001289 if (p == null) return null;
1290 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 }
1292
Nick Pellye0fd6932012-07-11 10:26:13 -07001293 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001295 checkPermission();
1296 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1297
1298 synchronized (mLock) {
1299 LocationProviderInterface p = mProvidersByName.get(provider);
1300 if (p == null) return false;
1301
1302 return isAllowedBySettingsLocked(provider);
1303 }
1304 }
1305
1306 private void checkCallerIsProvider() {
1307 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1308 == PackageManager.PERMISSION_GRANTED) {
1309 return;
1310 }
1311
1312 // Previously we only used the INSTALL_LOCATION_PROVIDER
1313 // check. But that is system or signature
1314 // protection level which is not flexible enough for
1315 // providers installed oustide the system image. So
1316 // also allow providers with a UID matching the
1317 // currently bound package name
1318
1319 int uid = Binder.getCallingUid();
1320
1321 if (mGeocodeProvider != null) {
1322 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1323 }
1324 for (LocationProviderProxy proxy : mProxyProviders) {
1325 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1326 }
1327 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1328 "or UID of a currently bound location provider");
1329 }
1330
1331 private boolean doesPackageHaveUid(int uid, String packageName) {
1332 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 return false;
1334 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001335 try {
1336 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1337 if (appInfo.uid != uid) {
1338 return false;
1339 }
1340 } catch (NameNotFoundException e) {
1341 return false;
1342 }
1343 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 }
1345
Nick Pellye0fd6932012-07-11 10:26:13 -07001346 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001347 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001348 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001349
Nick Pelly2eeeec22012-07-18 13:13:37 -07001350 if (!location.isComplete()) {
1351 Log.w(TAG, "Dropping incomplete location: " + location);
1352 return;
1353 }
1354
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001355 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1356 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001357 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001358 mLocationHandler.sendMessageAtFrontOfQueue(m);
1359 }
1360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361
1362 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1363 // Always broadcast the first update
1364 if (lastLoc == null) {
1365 return true;
1366 }
1367
Nick Pellyf1be6862012-05-15 10:53:42 -07001368 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001369 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001370 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001371 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 return false;
1373 }
1374
1375 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001376 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 if (minDistance > 0.0) {
1378 if (loc.distanceTo(lastLoc) <= minDistance) {
1379 return false;
1380 }
1381 }
1382
1383 return true;
1384 }
1385
Mike Lockwooda4903f22010-02-17 06:42:23 -05001386 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001387 if (D) Log.d(TAG, "incoming location: " + location);
1388
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001389 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001390 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001392 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001394 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001395 if (p == null) return;
1396
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001397 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001398 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1399 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001400 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001401 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001402 lastLocation = new Location(provider);
1403 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001404 } else {
1405 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1406 if (noGPSLocation == null && lastNoGPSLocation != null) {
1407 // New location has no no-GPS location: adopt last no-GPS location. This is set
1408 // directly into location because we do not want to notify COARSE clients.
1409 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1410 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001411 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001412 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413
Victoria Lease09016ab2012-09-16 12:33:15 -07001414 // Fetch coarse location
1415 Location coarseLocation = null;
1416 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1417 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1418 }
1419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 // Fetch latest status update time
1421 long newStatusUpdateTime = p.getStatusUpdateTime();
1422
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001423 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 Bundle extras = new Bundle();
1425 int status = p.getStatus(extras);
1426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001428 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001431 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001433 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001434
1435 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1436 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1437 receiver.mPackageName);
1438 continue;
1439 }
1440
Victoria Lease09016ab2012-09-16 12:33:15 -07001441 Location notifyLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001442 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001443 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001444 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001445 notifyLocation = coarseLocation; // use coarse location if available
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001446 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001447 if (notifyLocation != null) {
1448 Location lastLoc = r.mLastFixBroadcast;
1449 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1450 if (lastLoc == null) {
1451 lastLoc = new Location(notifyLocation);
1452 r.mLastFixBroadcast = lastLoc;
1453 } else {
1454 lastLoc.set(notifyLocation);
1455 }
1456 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1457 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1458 receiverDead = true;
1459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 }
1461 }
1462
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001463 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001465 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001467 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001469 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001470 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001471 }
1472 }
1473
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001474 // track expired records
1475 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1476 if (deadUpdateRecords == null) {
1477 deadUpdateRecords = new ArrayList<UpdateRecord>();
1478 }
1479 deadUpdateRecords.add(r);
1480 }
1481 // track dead receivers
1482 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001483 if (deadReceivers == null) {
1484 deadReceivers = new ArrayList<Receiver>();
1485 }
1486 if (!deadReceivers.contains(receiver)) {
1487 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 }
1489 }
1490 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001491
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001492 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001494 for (Receiver receiver : deadReceivers) {
1495 removeUpdatesLocked(receiver);
1496 }
1497 }
1498 if (deadUpdateRecords != null) {
1499 for (UpdateRecord r : deadUpdateRecords) {
1500 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 }
1502 }
1503 }
1504
1505 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506 @Override
1507 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001508 switch (msg.what) {
1509 case MSG_LOCATION_CHANGED:
1510 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1511 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 }
1513 }
1514 }
1515
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001516 private void handleLocationChanged(Location location, boolean passive) {
1517 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001518
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001519 if (!passive) {
1520 // notify passive provider of the new location
1521 mPassiveProvider.updateLocation(location);
1522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001524 synchronized (mLock) {
1525 if (isAllowedBySettingsLocked(provider)) {
1526 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530
Mike Lockwoode97ae402010-09-29 15:23:46 -04001531 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1532 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001533 public void onPackageDisappeared(String packageName, int reason) {
1534 // remove all receivers associated with this package name
1535 synchronized (mLock) {
1536 ArrayList<Receiver> deadReceivers = null;
1537
1538 for (Receiver receiver : mReceivers.values()) {
1539 if (receiver.mPackageName.equals(packageName)) {
1540 if (deadReceivers == null) {
1541 deadReceivers = new ArrayList<Receiver>();
1542 }
1543 deadReceivers.add(receiver);
1544 }
1545 }
1546
1547 // perform removal outside of mReceivers loop
1548 if (deadReceivers != null) {
1549 for (Receiver receiver : deadReceivers) {
1550 removeUpdatesLocked(receiver);
1551 }
1552 }
1553 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001554 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001555 };
1556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 // Wake locks
1558
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001559 private void incrementPendingBroadcasts() {
1560 synchronized (mWakeLock) {
1561 if (mPendingBroadcasts++ == 0) {
1562 try {
1563 mWakeLock.acquire();
1564 log("Acquired wakelock");
1565 } catch (Exception e) {
1566 // This is to catch a runtime exception thrown when we try to release an
1567 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001568 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001569 }
1570 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001571 }
1572 }
1573
1574 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001575 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001576 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001577 try {
1578 // Release wake lock
1579 if (mWakeLock.isHeld()) {
1580 mWakeLock.release();
1581 log("Released wakelock");
1582 } else {
1583 log("Can't release wakelock again!");
1584 }
1585 } catch (Exception e) {
1586 // This is to catch a runtime exception thrown when we try to release an
1587 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001588 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001589 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001590 }
1591 }
1592 }
1593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 // Geocoder
1595
Nick Pellye0fd6932012-07-11 10:26:13 -07001596 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001597 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001598 return mGeocodeProvider != null;
1599 }
1600
Nick Pellye0fd6932012-07-11 10:26:13 -07001601 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001602 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001603 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001604 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001605 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1606 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001608 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 }
1610
Mike Lockwooda55c3212009-04-15 11:10:11 -04001611
Nick Pellye0fd6932012-07-11 10:26:13 -07001612 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001614 double lowerLeftLatitude, double lowerLeftLongitude,
1615 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001616 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001617
1618 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001619 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1620 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1621 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001623 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 }
1625
1626 // Mock Providers
1627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 private void checkMockPermissionsSafe() {
1629 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1630 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1631 if (!allowMocks) {
1632 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1633 }
1634
1635 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1636 PackageManager.PERMISSION_GRANTED) {
1637 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 }
1640
Nick Pellye0fd6932012-07-11 10:26:13 -07001641 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001642 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 checkMockPermissionsSafe();
1644
Mike Lockwooda4903f22010-02-17 06:42:23 -05001645 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1646 throw new IllegalArgumentException("Cannot mock the passive location provider");
1647 }
1648
Mike Lockwood86328a92009-10-23 08:38:25 -04001649 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001650 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001651 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001652 // remove the real provider if we are replacing GPS or network provider
1653 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001654 || LocationManager.NETWORK_PROVIDER.equals(name)
1655 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001656 LocationProviderInterface p = mProvidersByName.get(name);
1657 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001658 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001659 }
1660 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001661 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1663 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001664 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001665 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001666 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 updateProvidersLocked();
1668 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001669 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 }
1671
Nick Pellye0fd6932012-07-11 10:26:13 -07001672 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 public void removeTestProvider(String provider) {
1674 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001675 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001676 MockProvider mockProvider = mMockProviders.get(provider);
1677 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1679 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001680 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001681 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001682 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001683
1684 // reinstate real provider if available
1685 LocationProviderInterface realProvider = mRealProviders.get(provider);
1686 if (realProvider != null) {
1687 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001688 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001689 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001691 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 }
1693 }
1694
Nick Pellye0fd6932012-07-11 10:26:13 -07001695 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 public void setTestProviderLocation(String provider, Location loc) {
1697 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001698 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001699 MockProvider mockProvider = mMockProviders.get(provider);
1700 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1702 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001703 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1704 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001705 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001706 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 }
1708 }
1709
Nick Pellye0fd6932012-07-11 10:26:13 -07001710 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 public void clearTestProviderLocation(String provider) {
1712 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001713 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001714 MockProvider mockProvider = mMockProviders.get(provider);
1715 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1717 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001718 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 }
1720 }
1721
Nick Pellye0fd6932012-07-11 10:26:13 -07001722 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 public void setTestProviderEnabled(String provider, boolean enabled) {
1724 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001725 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001726 MockProvider mockProvider = mMockProviders.get(provider);
1727 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1729 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001730 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001732 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 mEnabledProviders.add(provider);
1734 mDisabledProviders.remove(provider);
1735 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001736 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 mEnabledProviders.remove(provider);
1738 mDisabledProviders.add(provider);
1739 }
1740 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001741 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 }
1743 }
1744
Nick Pellye0fd6932012-07-11 10:26:13 -07001745 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 public void clearTestProviderEnabled(String provider) {
1747 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001748 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001749 MockProvider mockProvider = mMockProviders.get(provider);
1750 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1752 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001753 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 mEnabledProviders.remove(provider);
1755 mDisabledProviders.remove(provider);
1756 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001757 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 }
1759 }
1760
Nick Pellye0fd6932012-07-11 10:26:13 -07001761 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1763 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001764 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001765 MockProvider mockProvider = mMockProviders.get(provider);
1766 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1768 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001769 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 }
1771 }
1772
Nick Pellye0fd6932012-07-11 10:26:13 -07001773 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 public void clearTestProviderStatus(String provider) {
1775 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001776 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001777 MockProvider mockProvider = mMockProviders.get(provider);
1778 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1780 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001781 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 }
1783 }
1784
1785 private void log(String log) {
1786 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001787 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001788 }
1789 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001790
1791 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1793 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1794 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001795 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 + Binder.getCallingPid()
1797 + ", uid=" + Binder.getCallingUid());
1798 return;
1799 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001800
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001801 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001804 for (Receiver receiver : mReceivers.values()) {
1805 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001808 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1809 pw.println(" " + entry.getKey() + ":");
1810 for (UpdateRecord record : entry.getValue()) {
1811 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 }
1813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001815 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1816 String provider = entry.getKey();
1817 Location location = entry.getValue();
1818 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001820
Nick Pellye0fd6932012-07-11 10:26:13 -07001821 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001822
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 if (mEnabledProviders.size() > 0) {
1824 pw.println(" Enabled Providers:");
1825 for (String i : mEnabledProviders) {
1826 pw.println(" " + i);
1827 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 }
1830 if (mDisabledProviders.size() > 0) {
1831 pw.println(" Disabled Providers:");
1832 for (String i : mDisabledProviders) {
1833 pw.println(" " + i);
1834 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001836 pw.append(" ");
1837 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 if (mMockProviders.size() > 0) {
1839 pw.println(" Mock Providers:");
1840 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001841 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 }
1843 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001844
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001845 pw.append(" fudger: ");
1846 mLocationFudger.dump(fd, pw, args);
1847
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001848 if (args.length > 0 && "short".equals(args[0])) {
1849 return;
1850 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001851 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001852 pw.print(provider.getName() + " Internal State");
1853 if (provider instanceof LocationProviderProxy) {
1854 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1855 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001856 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001857 pw.println(":");
1858 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001859 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860 }
1861 }
1862}