blob: d982d0d3c2910be094569dc0d43d77ba9c3d11cf [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() {
250 if (GpsLocationProvider.isSupported()) {
251 // Create a gps location provider
252 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
253 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
254 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
255 addProviderLocked(gpsProvider);
256 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
257 }
258
259 // create a passive location provider, which is always enabled
260 PassiveProvider passiveProvider = new PassiveProvider(this);
261 addProviderLocked(passiveProvider);
262 mEnabledProviders.add(passiveProvider.getName());
263 mPassiveProvider = passiveProvider;
264
265 /*
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
648 * fused.
649 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700650 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700652 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700654 ArrayList<String> out;
655 synchronized (mLock) {
656 out = new ArrayList<String>(mProviders.size());
657 for (LocationProviderInterface provider : mProviders) {
658 String name = provider.getName();
659 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700660 continue;
661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 out.add(name);
663 }
664 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700665
666 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 return out;
668 }
669
Mike Lockwood03ca2162010-04-01 08:10:09 -0700670 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700671 * Return all providers by name, that match criteria and are optionally
672 * enabled.
673 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700674 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700675 @Override
676 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700677 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700678 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700679 out = new ArrayList<String>(mProviders.size());
680 for (LocationProviderInterface provider : mProviders) {
681 String name = provider.getName();
682 if (LocationManager.FUSED_PROVIDER.equals(name)) {
683 continue;
684 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700685 if (isAllowedProviderSafe(name)) {
686 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
687 continue;
688 }
689 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
690 name, provider.getProperties(), criteria)) {
691 continue;
692 }
693 out.add(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700694 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700695 }
696 }
697
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700698 if (D) Log.d(TAG, "getProviders()=" + out);
699 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700700 }
701
702 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700703 * Return the name of the best provider given a Criteria object.
704 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700705 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700706 * has been deprecated as well. So this method now uses
707 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700708 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700709 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700710 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700711 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700712
713 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700714 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700715 result = pickBest(providers);
716 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
717 return result;
718 }
719 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700720 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700721 result = pickBest(providers);
722 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
723 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700724 }
725
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700726 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700727 return null;
728 }
729
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700730 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700731 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700732 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700733 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
734 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700735 } else {
736 return providers.get(0);
737 }
738 }
739
Nick Pellye0fd6932012-07-11 10:26:13 -0700740 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700741 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700742 checkPermission();
743
Mike Lockwood03ca2162010-04-01 08:10:09 -0700744 LocationProviderInterface p = mProvidersByName.get(provider);
745 if (p == null) {
746 throw new IllegalArgumentException("provider=" + provider);
747 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700748
749 boolean result = LocationProvider.propertiesMeetCriteria(
750 p.getName(), p.getProperties(), criteria);
751 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
752 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700753 }
754
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700756 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400757 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500758 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 boolean isEnabled = p.isEnabled();
760 String name = p.getName();
761 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 if (isEnabled && !shouldBeEnabled) {
763 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700764 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 } else if (!isEnabled && shouldBeEnabled) {
766 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700767 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700769 }
770 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700771 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
772 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 }
774 }
775
776 private void updateProviderListenersLocked(String provider, boolean enabled) {
777 int listeners = 0;
778
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500779 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700780 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781
782 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
785 if (records != null) {
786 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700787 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 UpdateRecord record = records.get(i);
789 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700790 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
791 if (deadReceivers == null) {
792 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 }
Simon Schoar46866572009-06-10 21:12:10 +0200794 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 }
796 listeners++;
797 }
798 }
799
800 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700801 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 removeUpdatesLocked(deadReceivers.get(i));
803 }
804 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 if (enabled) {
807 p.enable();
808 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700809 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 }
811 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 }
815
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700816 private void applyRequirementsLocked(String provider) {
817 LocationProviderInterface p = mProvidersByName.get(provider);
818 if (p == null) return;
819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700821 WorkSource worksource = new WorkSource();
822 ProviderRequest providerRequest = new ProviderRequest();
823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700825 for (UpdateRecord record : records) {
826 LocationRequest locationRequest = record.mRequest;
827
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700828 providerRequest.locationRequests.add(locationRequest);
829 if (locationRequest.getInterval() < providerRequest.interval) {
830 providerRequest.reportLocation = true;
831 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700832 }
833 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700834
835 if (providerRequest.reportLocation) {
836 // calculate who to blame for power
837 // This is somewhat arbitrary. We pick a threshold interval
838 // that is slightly higher that the minimum interval, and
839 // spread the blame across all applications with a request
840 // under that threshold.
841 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
842 for (UpdateRecord record : records) {
843 LocationRequest locationRequest = record.mRequest;
844 if (locationRequest.getInterval() <= thresholdInterval) {
845 worksource.add(record.mReceiver.mUid);
846 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700847 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 }
849 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700850
851 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
852 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854
855 private class UpdateRecord {
856 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700857 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400859 Location mLastFixBroadcast;
860 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861
862 /**
863 * Note: must be constructed with lock held.
864 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700865 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700867 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869
870 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
871 if (records == null) {
872 records = new ArrayList<UpdateRecord>();
873 mRecordsByProvider.put(provider, records);
874 }
875 if (!records.contains(this)) {
876 records.add(this);
877 }
878 }
879
880 /**
881 * Method to be called when a record will no longer be used. Calling this multiple times
882 * must have the same effect as calling it once.
883 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700884 void disposeLocked(boolean removeReceiver) {
885 // remove from mRecordsByProvider
886 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
887 if (globalRecords != null) {
888 globalRecords.remove(this);
889 }
890
891 if (!removeReceiver) return; // the caller will handle the rest
892
893 // remove from Receiver#mUpdateRecords
894 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
895 if (receiverRecords != null) {
896 receiverRecords.remove(this.mProvider);
897
898 // and also remove the Receiver if it has no more update records
899 if (removeReceiver && receiverRecords.size() == 0) {
900 removeUpdatesLocked(mReceiver);
901 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 }
904
905 @Override
906 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700907 StringBuilder s = new StringBuilder();
908 s.append("UpdateRecord[");
909 s.append(mProvider);
910 s.append(' ').append(mReceiver.mPackageName).append('(');
911 s.append(mReceiver.mUid).append(')');
912 s.append(' ').append(mRequest);
913 s.append(']');
914 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 }
917
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700918 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400919 IBinder binder = listener.asBinder();
920 Receiver receiver = mReceivers.get(binder);
921 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700922 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400923 mReceivers.put(binder, receiver);
924
925 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700926 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400927 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800928 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400929 return null;
930 }
931 }
932 return receiver;
933 }
934
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700935 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400936 Receiver receiver = mReceivers.get(intent);
937 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700938 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400939 mReceivers.put(intent, receiver);
940 }
941 return receiver;
942 }
943
Victoria Lease09016ab2012-09-16 12:33:15 -0700944 private boolean isProviderAllowedByCoarsePermission(String provider) {
945 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
946 return true;
947 }
948 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
949 return true;
950 }
951 if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
952 return true;
953 }
954 return false;
955 }
956
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700957 private String checkPermissionAndRequest(LocationRequest request) {
958 String perm = checkPermission();
959
960 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Victoria Lease09016ab2012-09-16 12:33:15 -0700961 if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
962 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
963 }
964 switch (request.getQuality()) {
965 case LocationRequest.ACCURACY_FINE:
966 request.setQuality(LocationRequest.ACCURACY_BLOCK);
967 break;
968 case LocationRequest.POWER_HIGH:
969 request.setQuality(LocationRequest.POWER_LOW);
970 break;
971 }
972 // throttle
973 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
974 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
975 }
976 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
977 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
978 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700979 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700980 // make getFastestInterval() the minimum of interval and fastest interval
981 if (request.getFastestInterval() > request.getInterval()) {
982 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400983 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700984 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400985 }
986
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700987 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700988 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700989 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700990 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700991 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700992 String[] packages = mPackageManager.getPackagesForUid(uid);
993 if (packages == null) {
994 throw new SecurityException("invalid UID " + uid);
995 }
996 for (String pkg : packages) {
997 if (packageName.equals(pkg)) return;
998 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700999 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001000 }
1001
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001002 private void checkPendingIntent(PendingIntent intent) {
1003 if (intent == null) {
1004 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001005 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001006 }
1007
1008 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1009 int pid, int uid, String packageName) {
1010 if (intent == null && listener == null) {
1011 throw new IllegalArgumentException("need eiter listener or intent");
1012 } else if (intent != null && listener != null) {
1013 throw new IllegalArgumentException("cannot register both listener and intent");
1014 } else if (intent != null) {
1015 checkPendingIntent(intent);
1016 return getReceiver(intent, pid, uid, packageName);
1017 } else {
1018 return getReceiver(listener, pid, uid, packageName);
1019 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001020 }
1021
Nick Pellye0fd6932012-07-11 10:26:13 -07001022 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001023 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1024 PendingIntent intent, String packageName) {
1025 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1026 checkPackageName(packageName);
1027 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001029 final int pid = Binder.getCallingPid();
1030 final int uid = Binder.getCallingUid();
1031 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001033 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 long identity = Binder.clearCallingIdentity();
1035 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001036 synchronized (mLock) {
1037 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001038 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 } finally {
1040 Binder.restoreCallingIdentity(identity);
1041 }
1042 }
1043
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001044 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1045 int pid, int uid, String packageName) {
1046 // Figure out the provider. Either its explicitly request (legacy use cases), or
1047 // use the fused provider
1048 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1049 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001050 if (name == null) {
1051 throw new IllegalArgumentException("provider name must not be null");
1052 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001053 LocationProviderInterface provider = mProvidersByName.get(name);
1054 if (provider == null) {
1055 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1056 }
1057
1058 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1059 name + " " + request + " from " + packageName + "(" + uid + ")");
1060
1061 UpdateRecord record = new UpdateRecord(name, request, receiver);
1062 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1063 if (oldRecord != null) {
1064 oldRecord.disposeLocked(false);
1065 }
1066
1067 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1068 if (isProviderEnabled) {
1069 applyRequirementsLocked(name);
1070 } else {
1071 // Notify the listener that updates are currently disabled
1072 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 }
1074 }
1075
Nick Pellye0fd6932012-07-11 10:26:13 -07001076 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001077 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1078 String packageName) {
1079 checkPackageName(packageName);
1080 checkPermission();
1081 final int pid = Binder.getCallingPid();
1082 final int uid = Binder.getCallingUid();
1083 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1084
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001085 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001086 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001088 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001089 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001091 } finally {
1092 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 }
1094 }
1095
1096 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001097 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1098
1099 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1100 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1101 synchronized (receiver) {
1102 if (receiver.mPendingBroadcasts > 0) {
1103 decrementPendingBroadcasts();
1104 receiver.mPendingBroadcasts = 0;
1105 }
1106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 }
1108
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001109 // Record which providers were associated with this listener
1110 HashSet<String> providers = new HashSet<String>();
1111 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1112 if (oldRecords != null) {
1113 // Call dispose() on the obsolete update records.
1114 for (UpdateRecord record : oldRecords.values()) {
1115 record.disposeLocked(false);
1116 }
1117 // Accumulate providers
1118 providers.addAll(oldRecords.keySet());
1119 }
1120
1121 // update provider
1122 for (String provider : providers) {
1123 // If provider is already disabled, don't need to do anything
1124 if (!isAllowedBySettingsLocked(provider)) {
1125 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126 }
1127
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001128 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 }
1130 }
1131
Nick Pellye0fd6932012-07-11 10:26:13 -07001132 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001133 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001134 if (D) Log.d(TAG, "getLastLocation: " + request);
1135 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1136 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001137 checkPackageName(packageName);
1138
1139 if (mBlacklist.isBlacklisted(packageName)) {
1140 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1141 packageName);
1142 return null;
1143 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001144
1145 synchronized (mLock) {
1146 // Figure out the provider. Either its explicitly request (deprecated API's),
1147 // or use the fused provider
1148 String name = request.getProvider();
1149 if (name == null) name = LocationManager.FUSED_PROVIDER;
1150 LocationProviderInterface provider = mProvidersByName.get(name);
1151 if (provider == null) return null;
1152
1153 if (!isAllowedBySettingsLocked(name)) return null;
1154
1155 Location location = mLastLocation.get(name);
Victoria Lease09016ab2012-09-16 12:33:15 -07001156 if (location == null) {
1157 return null;
1158 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001159 if (ACCESS_FINE_LOCATION.equals(perm)) {
1160 return location;
1161 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001162 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1163 if (noGPSLocation != null) {
1164 return mLocationFudger.getOrCreate(noGPSLocation);
1165 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001166 }
1167 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001168 return null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001169 }
1170
1171 @Override
1172 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1173 String packageName) {
1174 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001175 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001176 checkPermissionAndRequest(request);
1177 checkPendingIntent(intent);
1178 checkPackageName(packageName);
1179
1180 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1181
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001182 // geo-fence manager uses the public location API, need to clear identity
1183 int uid = Binder.getCallingUid();
1184 long identity = Binder.clearCallingIdentity();
1185 try {
1186 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1187 } finally {
1188 Binder.restoreCallingIdentity(identity);
1189 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001190 }
1191
1192 @Override
1193 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001194 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001195 checkPendingIntent(intent);
1196 checkPackageName(packageName);
1197
1198 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1199
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001200 // geo-fence manager uses the public location API, need to clear identity
1201 long identity = Binder.clearCallingIdentity();
1202 try {
1203 mGeofenceManager.removeFence(geofence, intent);
1204 } finally {
1205 Binder.restoreCallingIdentity(identity);
1206 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001207 }
1208
1209
1210 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001212 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 return false;
1214 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001215 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 PackageManager.PERMISSION_GRANTED) {
1217 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1218 }
1219
1220 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001221 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001223 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 return false;
1225 }
1226 return true;
1227 }
1228
Nick Pellye0fd6932012-07-11 10:26:13 -07001229 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001231 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001232 try {
1233 mGpsStatusProvider.removeGpsStatusListener(listener);
1234 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001235 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001236 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 }
1238 }
1239
Nick Pellye0fd6932012-07-11 10:26:13 -07001240 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001242 if (provider == null) {
1243 // throw NullPointerException to remain compatible with previous implementation
1244 throw new NullPointerException();
1245 }
1246
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001247 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001249 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 != PackageManager.PERMISSION_GRANTED)) {
1251 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1252 }
1253
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001254 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001255 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001256 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001257
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001258 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 }
1260 }
1261
Nick Pellye0fd6932012-07-11 10:26:13 -07001262 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001263 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001264 if (Binder.getCallingUid() != Process.myUid()) {
1265 throw new SecurityException(
1266 "calling sendNiResponse from outside of the system is not allowed");
1267 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001268 try {
1269 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001270 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001271 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001272 return false;
1273 }
1274 }
1275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001277 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001278 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 * accessed by the caller
1280 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001281 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001282 public ProviderProperties getProviderProperties(String provider) {
1283 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001285 LocationProviderInterface p;
1286 synchronized (mLock) {
1287 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 }
1289
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001290 if (p == null) return null;
1291 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 }
1293
Nick Pellye0fd6932012-07-11 10:26:13 -07001294 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001296 checkPermission();
1297 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1298
1299 synchronized (mLock) {
1300 LocationProviderInterface p = mProvidersByName.get(provider);
1301 if (p == null) return false;
1302
1303 return isAllowedBySettingsLocked(provider);
1304 }
1305 }
1306
1307 private void checkCallerIsProvider() {
1308 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1309 == PackageManager.PERMISSION_GRANTED) {
1310 return;
1311 }
1312
1313 // Previously we only used the INSTALL_LOCATION_PROVIDER
1314 // check. But that is system or signature
1315 // protection level which is not flexible enough for
1316 // providers installed oustide the system image. So
1317 // also allow providers with a UID matching the
1318 // currently bound package name
1319
1320 int uid = Binder.getCallingUid();
1321
1322 if (mGeocodeProvider != null) {
1323 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1324 }
1325 for (LocationProviderProxy proxy : mProxyProviders) {
1326 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1327 }
1328 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1329 "or UID of a currently bound location provider");
1330 }
1331
1332 private boolean doesPackageHaveUid(int uid, String packageName) {
1333 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 return false;
1335 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001336 try {
1337 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1338 if (appInfo.uid != uid) {
1339 return false;
1340 }
1341 } catch (NameNotFoundException e) {
1342 return false;
1343 }
1344 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 }
1346
Nick Pellye0fd6932012-07-11 10:26:13 -07001347 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001348 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001349 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001350
Nick Pelly2eeeec22012-07-18 13:13:37 -07001351 if (!location.isComplete()) {
1352 Log.w(TAG, "Dropping incomplete location: " + location);
1353 return;
1354 }
1355
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001356 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1357 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001358 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001359 mLocationHandler.sendMessageAtFrontOfQueue(m);
1360 }
1361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362
1363 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1364 // Always broadcast the first update
1365 if (lastLoc == null) {
1366 return true;
1367 }
1368
Nick Pellyf1be6862012-05-15 10:53:42 -07001369 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001370 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001371 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001372 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 return false;
1374 }
1375
1376 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001377 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 if (minDistance > 0.0) {
1379 if (loc.distanceTo(lastLoc) <= minDistance) {
1380 return false;
1381 }
1382 }
1383
1384 return true;
1385 }
1386
Mike Lockwooda4903f22010-02-17 06:42:23 -05001387 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001388 if (D) Log.d(TAG, "incoming location: " + location);
1389
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001390 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001391 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001393 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001395 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001396 if (p == null) return;
1397
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001398 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001399 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1400 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001401 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001402 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001403 lastLocation = new Location(provider);
1404 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001405 } else {
1406 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1407 if (noGPSLocation == null && lastNoGPSLocation != null) {
1408 // New location has no no-GPS location: adopt last no-GPS location. This is set
1409 // directly into location because we do not want to notify COARSE clients.
1410 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1411 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001412 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001413 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414
Victoria Lease09016ab2012-09-16 12:33:15 -07001415 // Fetch coarse location
1416 Location coarseLocation = null;
1417 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1418 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1419 }
1420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 // Fetch latest status update time
1422 long newStatusUpdateTime = p.getStatusUpdateTime();
1423
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001424 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 Bundle extras = new Bundle();
1426 int status = p.getStatus(extras);
1427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001429 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001432 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001434 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001435
1436 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1437 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1438 receiver.mPackageName);
1439 continue;
1440 }
1441
Victoria Lease09016ab2012-09-16 12:33:15 -07001442 Location notifyLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001443 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001444 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001445 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001446 notifyLocation = coarseLocation; // use coarse location if available
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001447 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001448 if (notifyLocation != null) {
1449 Location lastLoc = r.mLastFixBroadcast;
1450 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1451 if (lastLoc == null) {
1452 lastLoc = new Location(notifyLocation);
1453 r.mLastFixBroadcast = lastLoc;
1454 } else {
1455 lastLoc.set(notifyLocation);
1456 }
1457 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1458 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1459 receiverDead = true;
1460 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 }
1462 }
1463
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001464 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001466 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001468 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001470 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001471 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001472 }
1473 }
1474
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001475 // track expired records
1476 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1477 if (deadUpdateRecords == null) {
1478 deadUpdateRecords = new ArrayList<UpdateRecord>();
1479 }
1480 deadUpdateRecords.add(r);
1481 }
1482 // track dead receivers
1483 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001484 if (deadReceivers == null) {
1485 deadReceivers = new ArrayList<Receiver>();
1486 }
1487 if (!deadReceivers.contains(receiver)) {
1488 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 }
1490 }
1491 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001492
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001493 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001495 for (Receiver receiver : deadReceivers) {
1496 removeUpdatesLocked(receiver);
1497 }
1498 }
1499 if (deadUpdateRecords != null) {
1500 for (UpdateRecord r : deadUpdateRecords) {
1501 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 }
1503 }
1504 }
1505
1506 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 @Override
1508 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001509 switch (msg.what) {
1510 case MSG_LOCATION_CHANGED:
1511 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1512 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 }
1514 }
1515 }
1516
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001517 private void handleLocationChanged(Location location, boolean passive) {
1518 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001519
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001520 if (!passive) {
1521 // notify passive provider of the new location
1522 mPassiveProvider.updateLocation(location);
1523 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001525 synchronized (mLock) {
1526 if (isAllowedBySettingsLocked(provider)) {
1527 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001530 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531
Mike Lockwoode97ae402010-09-29 15:23:46 -04001532 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1533 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001534 public void onPackageDisappeared(String packageName, int reason) {
1535 // remove all receivers associated with this package name
1536 synchronized (mLock) {
1537 ArrayList<Receiver> deadReceivers = null;
1538
1539 for (Receiver receiver : mReceivers.values()) {
1540 if (receiver.mPackageName.equals(packageName)) {
1541 if (deadReceivers == null) {
1542 deadReceivers = new ArrayList<Receiver>();
1543 }
1544 deadReceivers.add(receiver);
1545 }
1546 }
1547
1548 // perform removal outside of mReceivers loop
1549 if (deadReceivers != null) {
1550 for (Receiver receiver : deadReceivers) {
1551 removeUpdatesLocked(receiver);
1552 }
1553 }
1554 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001555 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001556 };
1557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 // Wake locks
1559
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001560 private void incrementPendingBroadcasts() {
1561 synchronized (mWakeLock) {
1562 if (mPendingBroadcasts++ == 0) {
1563 try {
1564 mWakeLock.acquire();
1565 log("Acquired wakelock");
1566 } catch (Exception e) {
1567 // This is to catch a runtime exception thrown when we try to release an
1568 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001569 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001570 }
1571 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001572 }
1573 }
1574
1575 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001576 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001577 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001578 try {
1579 // Release wake lock
1580 if (mWakeLock.isHeld()) {
1581 mWakeLock.release();
1582 log("Released wakelock");
1583 } else {
1584 log("Can't release wakelock again!");
1585 }
1586 } catch (Exception e) {
1587 // This is to catch a runtime exception thrown when we try to release an
1588 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001589 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001590 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001591 }
1592 }
1593 }
1594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 // Geocoder
1596
Nick Pellye0fd6932012-07-11 10:26:13 -07001597 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001598 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001599 return mGeocodeProvider != null;
1600 }
1601
Nick Pellye0fd6932012-07-11 10:26:13 -07001602 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001604 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001605 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001606 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1607 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001609 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 }
1611
Mike Lockwooda55c3212009-04-15 11:10:11 -04001612
Nick Pellye0fd6932012-07-11 10:26:13 -07001613 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001615 double lowerLeftLatitude, double lowerLeftLongitude,
1616 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001617 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001618
1619 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001620 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1621 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1622 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001624 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 }
1626
1627 // Mock Providers
1628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 private void checkMockPermissionsSafe() {
1630 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1631 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1632 if (!allowMocks) {
1633 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1634 }
1635
1636 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1637 PackageManager.PERMISSION_GRANTED) {
1638 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001639 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 }
1641
Nick Pellye0fd6932012-07-11 10:26:13 -07001642 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001643 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 checkMockPermissionsSafe();
1645
Mike Lockwooda4903f22010-02-17 06:42:23 -05001646 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1647 throw new IllegalArgumentException("Cannot mock the passive location provider");
1648 }
1649
Mike Lockwood86328a92009-10-23 08:38:25 -04001650 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001651 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001652 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001653 // remove the real provider if we are replacing GPS or network provider
1654 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001655 || LocationManager.NETWORK_PROVIDER.equals(name)
1656 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001657 LocationProviderInterface p = mProvidersByName.get(name);
1658 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001659 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001660 }
1661 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001662 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1664 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001665 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001666 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001667 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 updateProvidersLocked();
1669 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001670 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
1672
Nick Pellye0fd6932012-07-11 10:26:13 -07001673 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 public void removeTestProvider(String provider) {
1675 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001676 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001677 MockProvider mockProvider = mMockProviders.get(provider);
1678 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1680 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001681 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001682 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001683 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001684
1685 // reinstate real provider if available
1686 LocationProviderInterface realProvider = mRealProviders.get(provider);
1687 if (realProvider != null) {
1688 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001689 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001690 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001692 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 }
1694 }
1695
Nick Pellye0fd6932012-07-11 10:26:13 -07001696 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 public void setTestProviderLocation(String provider, Location loc) {
1698 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001699 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001700 MockProvider mockProvider = mMockProviders.get(provider);
1701 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1703 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001704 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1705 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001706 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001707 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 }
1709 }
1710
Nick Pellye0fd6932012-07-11 10:26:13 -07001711 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 public void clearTestProviderLocation(String provider) {
1713 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001714 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001715 MockProvider mockProvider = mMockProviders.get(provider);
1716 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1718 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001719 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 }
1721 }
1722
Nick Pellye0fd6932012-07-11 10:26:13 -07001723 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 public void setTestProviderEnabled(String provider, boolean enabled) {
1725 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001726 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001727 MockProvider mockProvider = mMockProviders.get(provider);
1728 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1730 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001731 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001733 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 mEnabledProviders.add(provider);
1735 mDisabledProviders.remove(provider);
1736 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001737 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 mEnabledProviders.remove(provider);
1739 mDisabledProviders.add(provider);
1740 }
1741 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001742 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 }
1744 }
1745
Nick Pellye0fd6932012-07-11 10:26:13 -07001746 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 public void clearTestProviderEnabled(String provider) {
1748 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001749 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001750 MockProvider mockProvider = mMockProviders.get(provider);
1751 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1753 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001754 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 mEnabledProviders.remove(provider);
1756 mDisabledProviders.remove(provider);
1757 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001758 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 }
1760 }
1761
Nick Pellye0fd6932012-07-11 10:26:13 -07001762 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1764 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001765 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001766 MockProvider mockProvider = mMockProviders.get(provider);
1767 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1769 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001770 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 }
1772 }
1773
Nick Pellye0fd6932012-07-11 10:26:13 -07001774 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 public void clearTestProviderStatus(String provider) {
1776 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001777 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001778 MockProvider mockProvider = mMockProviders.get(provider);
1779 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1781 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001782 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 }
1784 }
1785
1786 private void log(String log) {
1787 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001788 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 }
1790 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001791
1792 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1794 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1795 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001796 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 + Binder.getCallingPid()
1798 + ", uid=" + Binder.getCallingUid());
1799 return;
1800 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001801
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001802 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001805 for (Receiver receiver : mReceivers.values()) {
1806 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001809 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1810 pw.println(" " + entry.getKey() + ":");
1811 for (UpdateRecord record : entry.getValue()) {
1812 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813 }
1814 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001816 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1817 String provider = entry.getKey();
1818 Location location = entry.getValue();
1819 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001821
Nick Pellye0fd6932012-07-11 10:26:13 -07001822 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 if (mEnabledProviders.size() > 0) {
1825 pw.println(" Enabled Providers:");
1826 for (String i : mEnabledProviders) {
1827 pw.println(" " + i);
1828 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 }
1831 if (mDisabledProviders.size() > 0) {
1832 pw.println(" Disabled Providers:");
1833 for (String i : mDisabledProviders) {
1834 pw.println(" " + i);
1835 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001837 pw.append(" ");
1838 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001839 if (mMockProviders.size() > 0) {
1840 pw.println(" Mock Providers:");
1841 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001842 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 }
1844 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001845
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001846 pw.append(" fudger: ");
1847 mLocationFudger.dump(fd, pw, args);
1848
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001849 if (args.length > 0 && "short".equals(args[0])) {
1850 return;
1851 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001852 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001853 pw.print(provider.getName() + " Internal State");
1854 if (provider instanceof LocationProviderProxy) {
1855 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1856 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001857 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001858 pw.println(":");
1859 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001860 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 }
1862 }
1863}