blob: 91f63da74976302b99f3c88558c97689bf004b26 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070020import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070024import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070027import android.content.pm.PackageManager.NameNotFoundException;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050028import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070029import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070031import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050032import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070033import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040035import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.location.ILocationListener;
37import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040038import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.Location;
40import android.location.LocationManager;
41import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070042import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.os.Binder;
44import android.os.Bundle;
45import android.os.Handler;
46import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070047import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.Message;
49import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070050import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070052import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070053import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070054import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080057import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
Mike Lockwoode97ae402010-09-29 15:23:46 -040059import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070060import com.android.internal.location.ProviderProperties;
61import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040062import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070063import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040064import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070065import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070066import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040067import com.android.server.location.LocationProviderInterface;
68import com.android.server.location.LocationProviderProxy;
69import com.android.server.location.MockProvider;
70import com.android.server.location.PassiveProvider;
71
72import java.io.FileDescriptor;
73import java.io.PrintWriter;
74import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070075import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040076import java.util.HashMap;
77import java.util.HashSet;
78import java.util.List;
79import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040080import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081
82/**
83 * The service class that manages LocationProviders and issues location
84 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 */
Brian Muramatsubb95cb92012-08-29 10:43:21 -070086public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070088 public static final boolean D = false;
89
90 private static final String WAKELOCK_KEY = TAG;
91 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 private static final String ACCESS_FINE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070094 android.Manifest.permission.ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 private static final String ACCESS_COARSE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070096 android.Manifest.permission.ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070098 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700100 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400101 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700102 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
103
104 private static final String NETWORK_LOCATION_SERVICE_ACTION =
105 "com.android.location.service.v2.NetworkLocationProvider";
106 private static final String FUSED_LOCATION_SERVICE_ACTION =
107 "com.android.location.service.FusedLocationProvider";
108
109 private static final int MSG_LOCATION_CHANGED = 1;
110
Nick Pellyf1be6862012-05-15 10:53:42 -0700111 // Location Providers may sometimes deliver location updates
112 // slightly faster that requested - provide grace period so
113 // we don't unnecessarily filter events that are otherwise on
114 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700115 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700116
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700117 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
118
119 private final Context mContext;
120
121 // used internally for synchronization
122 private final Object mLock = new Object();
123
124 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700125 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700126 private GeofenceManager mGeofenceManager;
127 private PowerManager.WakeLock mWakeLock;
128 private PackageManager mPackageManager;
129 private GeocoderProxy mGeocodeProvider;
130 private IGpsStatusProvider mGpsStatusProvider;
131 private INetInitiatedListener mNetInitiatedListener;
132 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700133 private PassiveProvider mPassiveProvider; // track passive provider for special cases
134 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700135
136 // --- fields below are protected by mWakeLock ---
137 private int mPendingBroadcasts;
138
139 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 // Set of providers that are explicitly enabled
141 private final Set<String> mEnabledProviders = new HashSet<String>();
142
143 // Set of providers that are explicitly disabled
144 private final Set<String> mDisabledProviders = new HashSet<String>();
145
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700146 // Mock (test) providers
147 private final HashMap<String, MockProvider> mMockProviders =
148 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700150 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400151 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700153 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500154 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400156
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700157 // real providers, saved here when mocked out
158 private final HashMap<String, LocationProviderInterface> mRealProviders =
159 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700161 // mapping from provider name to provider
162 private final HashMap<String, LocationProviderInterface> mProvidersByName =
163 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700165 // mapping from provider name to all its UpdateRecords
166 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
167 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // mapping from provider name to last known location
170 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172 // all providers that operate over proxy, for authorizing incoming location
173 private final ArrayList<LocationProviderProxy> mProxyProviders =
174 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175
Victoria Lease38389b62012-09-30 11:44:22 -0700176 // current active user on the device - other users are denied location data
177 private int mCurrentUserId = UserHandle.USER_OWNER;
178
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700179 public LocationManagerService(Context context) {
180 super();
181 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800182
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 if (D) Log.d(TAG, "Constructed");
184
185 // most startup is deferred until systemReady()
186 }
187
188 public void systemReady() {
189 Thread thread = new Thread(null, this, THREAD_NAME);
190 thread.start();
191 }
192
193 @Override
194 public void run() {
195 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
196 Looper.prepare();
197 mLocationHandler = new LocationWorkerHandler();
198 init();
199 Looper.loop();
200 }
201
202 private void init() {
203 if (D) Log.d(TAG, "init()");
204
205 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
206 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
207 mPackageManager = mContext.getPackageManager();
208
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700209 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
210 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700211 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700212
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700213 synchronized (mLock) {
214 loadProvidersLocked();
215 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700216
Nick Pelly4035f5a2012-08-17 14:43:49 -0700217 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700218
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700219 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700220 mContext.getContentResolver().registerContentObserver(
221 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
222 new ContentObserver(mLocationHandler) {
223 @Override
224 public void onChange(boolean selfChange) {
225 synchronized (mLock) {
226 updateProvidersLocked();
227 }
228 }
229 });
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700230 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700231
Victoria Lease38389b62012-09-30 11:44:22 -0700232 // listen for user change
233 IntentFilter intentFilter = new IntentFilter();
234 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
235
236 mContext.registerReceiverAsUser(new BroadcastReceiver() {
237 @Override
238 public void onReceive(Context context, Intent intent) {
239 String action = intent.getAction();
240 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
241 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
242 }
243 }
244 }, UserHandle.ALL, intentFilter, null, null);
245
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700246 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700247 }
248
249 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700250 // create a passive location provider, which is always enabled
251 PassiveProvider passiveProvider = new PassiveProvider(this);
252 addProviderLocked(passiveProvider);
253 mEnabledProviders.add(passiveProvider.getName());
254 mPassiveProvider = passiveProvider;
255
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700256 if (GpsLocationProvider.isSupported()) {
257 // Create a gps location provider
258 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
259 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
260 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
261 addProviderLocked(gpsProvider);
262 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
263 }
264
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700265 /*
266 Load package name(s) containing location provider support.
267 These packages can contain services implementing location providers:
268 Geocoder Provider, Network Location Provider, and
269 Fused Location Provider. They will each be searched for
270 service components implementing these providers.
271 The location framework also has support for installation
272 of new location providers at run-time. The new package does not
273 have to be explicitly listed here, however it must have a signature
274 that matches the signature of at least one package on this list.
275 */
276 Resources resources = mContext.getResources();
277 ArrayList<String> providerPackageNames = new ArrayList<String>();
278 String[] pkgs1 = resources.getStringArray(
279 com.android.internal.R.array.config_locationProviderPackageNames);
280 String[] pkgs2 = resources.getStringArray(
281 com.android.internal.R.array.config_overlay_locationProviderPackageNames);
282 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
283 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
284 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
285 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
286
287 // bind to network provider
288 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
289 mContext,
290 LocationManager.NETWORK_PROVIDER,
291 NETWORK_LOCATION_SERVICE_ACTION,
292 providerPackageNames, mLocationHandler);
293 if (networkProvider != null) {
294 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
295 mProxyProviders.add(networkProvider);
296 addProviderLocked(networkProvider);
297 } else {
298 Slog.w(TAG, "no network location provider found");
299 }
300
301 // bind to fused provider
302 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
303 mContext,
304 LocationManager.FUSED_PROVIDER,
305 FUSED_LOCATION_SERVICE_ACTION,
306 providerPackageNames, mLocationHandler);
307 if (fusedLocationProvider != null) {
308 addProviderLocked(fusedLocationProvider);
309 mProxyProviders.add(fusedLocationProvider);
310 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700311 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700312 } else {
313 Slog.e(TAG, "no fused location provider found",
314 new IllegalStateException("Location service needs a fused location provider"));
315 }
316
317 // bind to geocoder provider
318 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
319 if (mGeocodeProvider == null) {
320 Slog.e(TAG, "no geocoder provider found");
321 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700322 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700325 * Called when the device's active user changes.
326 * @param userId the new active user's UserId
327 */
328 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700329 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700330 //Log.d("LocationManagerService", "switchUser(" + mCurrentUserId + " -> " + userId + ")"); // TODO: remove this
331 synchronized (mLock) {
332 // TODO: inform previous user's Receivers that they will no longer receive updates
333 mCurrentUserId = userId;
334 // TODO: inform new user's Receivers that they are back on the update train
335 }
336 }
337
338 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
340 * location updates.
341 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700342 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700343 final int mUid; // uid of receiver
344 final int mPid; // pid of receiver
345 final String mPackageName; // package name of receiver
346 final String mPermission; // best permission that receiver has
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 final ILocationListener mListener;
349 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700351
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400352 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700353
Mike Lockwood48f17512009-04-23 09:12:08 -0700354 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700356 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
357 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700360 if (listener != null) {
361 mKey = listener.asBinder();
362 } else {
363 mKey = intent;
364 }
365 mPermission = checkPermission();
366 mUid = uid;
367 mPid = pid;
368 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 }
370
371 @Override
372 public boolean equals(Object otherObj) {
373 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700374 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 }
376 return false;
377 }
378
379 @Override
380 public int hashCode() {
381 return mKey.hashCode();
382 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 @Override
385 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700386 StringBuilder s = new StringBuilder();
387 s.append("Reciever[");
388 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700390 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700392 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700394 for (String p : mUpdateRecords.keySet()) {
395 s.append(" ").append(mUpdateRecords.get(p).toString());
396 }
397 s.append("]");
398 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 }
400
401 public boolean isListener() {
402 return mListener != null;
403 }
404
405 public boolean isPendingIntent() {
406 return mPendingIntent != null;
407 }
408
409 public ILocationListener getListener() {
410 if (mListener != null) {
411 return mListener;
412 }
413 throw new IllegalStateException("Request for non-existent listener");
414 }
415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
417 if (mListener != null) {
418 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700419 synchronized (this) {
420 // synchronize to ensure incrementPendingBroadcastsLocked()
421 // is called before decrementPendingBroadcasts()
422 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700423 // call this after broadcasting so we do not increment
424 // if we throw an exeption.
425 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700426 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 } catch (RemoteException e) {
428 return false;
429 }
430 } else {
431 Intent statusChanged = new Intent();
432 statusChanged.putExtras(extras);
433 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
434 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700435 synchronized (this) {
436 // synchronize to ensure incrementPendingBroadcastsLocked()
437 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700438 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700439 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700440 // call this after broadcasting so we do not increment
441 // if we throw an exeption.
442 incrementPendingBroadcastsLocked();
443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 } catch (PendingIntent.CanceledException e) {
445 return false;
446 }
447 }
448 return true;
449 }
450
451 public boolean callLocationChangedLocked(Location location) {
452 if (mListener != null) {
453 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700454 synchronized (this) {
455 // synchronize to ensure incrementPendingBroadcastsLocked()
456 // is called before decrementPendingBroadcasts()
457 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700458 // call this after broadcasting so we do not increment
459 // if we throw an exeption.
460 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700461 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 } catch (RemoteException e) {
463 return false;
464 }
465 } else {
466 Intent locationChanged = new Intent();
467 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
468 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700469 synchronized (this) {
470 // synchronize to ensure incrementPendingBroadcastsLocked()
471 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700472 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700473 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700474 // call this after broadcasting so we do not increment
475 // if we throw an exeption.
476 incrementPendingBroadcastsLocked();
477 }
478 } catch (PendingIntent.CanceledException e) {
479 return false;
480 }
481 }
482 return true;
483 }
484
485 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
486 if (mListener != null) {
487 try {
488 synchronized (this) {
489 // synchronize to ensure incrementPendingBroadcastsLocked()
490 // is called before decrementPendingBroadcasts()
491 if (enabled) {
492 mListener.onProviderEnabled(provider);
493 } else {
494 mListener.onProviderDisabled(provider);
495 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700496 // call this after broadcasting so we do not increment
497 // if we throw an exeption.
498 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700499 }
500 } catch (RemoteException e) {
501 return false;
502 }
503 } else {
504 Intent providerIntent = new Intent();
505 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
506 try {
507 synchronized (this) {
508 // synchronize to ensure incrementPendingBroadcastsLocked()
509 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700510 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700511 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700512 // call this after broadcasting so we do not increment
513 // if we throw an exeption.
514 incrementPendingBroadcastsLocked();
515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 } catch (PendingIntent.CanceledException e) {
517 return false;
518 }
519 }
520 return true;
521 }
522
Nick Pellyf1be6862012-05-15 10:53:42 -0700523 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700525 if (D) Log.d(TAG, "Location listener died");
526
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400527 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 removeUpdatesLocked(this);
529 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700530 synchronized (this) {
531 if (mPendingBroadcasts > 0) {
532 LocationManagerService.this.decrementPendingBroadcasts();
533 mPendingBroadcasts = 0;
534 }
535 }
536 }
537
Nick Pellye0fd6932012-07-11 10:26:13 -0700538 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700539 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
540 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400541 synchronized (this) {
542 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700543 }
544 }
545
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400546 // this must be called while synchronized by caller in a synchronized block
547 // containing the sending of the broadcaset
548 private void incrementPendingBroadcastsLocked() {
549 if (mPendingBroadcasts++ == 0) {
550 LocationManagerService.this.incrementPendingBroadcasts();
551 }
552 }
553
554 private void decrementPendingBroadcastsLocked() {
555 if (--mPendingBroadcasts == 0) {
556 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700557 }
558 }
559 }
560
Nick Pellye0fd6932012-07-11 10:26:13 -0700561 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700562 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400563 //Do not use getReceiver here as that will add the ILocationListener to
564 //the receiver list if it is not found. If it is not found then the
565 //LocationListener was removed when it had a pending broadcast and should
566 //not be added back.
567 IBinder binder = listener.asBinder();
568 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700569 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400570 synchronized (receiver) {
571 // so wakelock calls will succeed
572 long identity = Binder.clearCallingIdentity();
573 receiver.decrementPendingBroadcastsLocked();
574 Binder.restoreCallingIdentity(identity);
575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 }
577 }
578
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700579 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400580 mProviders.add(provider);
581 mProvidersByName.put(provider.getName(), provider);
582 }
583
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700584 private void removeProviderLocked(LocationProviderInterface provider) {
585 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400586 mProviders.remove(provider);
587 mProvidersByName.remove(provider.getName());
588 }
589
Mike Lockwood3d12b512009-04-21 23:25:35 -0700590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 private boolean isAllowedBySettingsLocked(String provider) {
592 if (mEnabledProviders.contains(provider)) {
593 return true;
594 }
595 if (mDisabledProviders.contains(provider)) {
596 return false;
597 }
598 // Use system settings
599 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600
Brad Larson8eb3ea62009-12-29 11:47:55 -0600601 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 }
603
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700604 /**
605 * Throw SecurityException if caller has neither COARSE or FINE.
606 * Otherwise, return the best permission.
607 */
608 private String checkPermission() {
609 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
610 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700611 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700612 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
613 PackageManager.PERMISSION_GRANTED) {
614 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700616
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700617 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
Victoria Lease4fab68b2012-09-13 13:20:59 -0700618 " ACCESS_FINE_LOCATION permission");
619 }
620
621 /**
622 * Throw SecurityException if caller lacks permission to use Geofences.
623 */
624 private void checkGeofencePermission() {
625 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
626 PackageManager.PERMISSION_GRANTED) {
627 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
628 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 }
630
Victoria Lease8dbb6342012-09-21 16:55:53 -0700631 private boolean isAllowedProviderSafe(String provider) {
632 if (LocationManager.GPS_PROVIDER.equals(provider) ||
633 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
634 // gps and passive providers require FINE permission
635 return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
636 == PackageManager.PERMISSION_GRANTED;
637 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
638 LocationManager.FUSED_PROVIDER.equals(provider)) {
639 // network and fused providers are ok with COARSE or FINE
640 return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
641 == PackageManager.PERMISSION_GRANTED) ||
642 (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
643 == PackageManager.PERMISSION_GRANTED);
Laurent Tu941221c2012-10-04 14:21:52 -0700644 } else {
645 // mock providers
646 LocationProviderInterface lp = mMockProviders.get(provider);
647 if (lp != null) {
648 ProviderProperties properties = lp.getProperties();
649 if (properties != null) {
650 if (properties.mRequiresSatellite) {
651 // provider requiring satellites require FINE permission
652 return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
653 == PackageManager.PERMISSION_GRANTED;
654 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
655 // provider requiring network and or cell require COARSE or FINE
656 return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
657 == PackageManager.PERMISSION_GRANTED) ||
658 (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
659 == PackageManager.PERMISSION_GRANTED);
660 }
661 }
662 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700663 }
Laurent Tu941221c2012-10-04 14:21:52 -0700664
Victoria Lease8dbb6342012-09-21 16:55:53 -0700665 return false;
666 }
667
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700668 /**
669 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700670 * fused, also including ones that are not permitted to
671 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700672 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700673 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700675 ArrayList<String> out;
676 synchronized (mLock) {
677 out = new ArrayList<String>(mProviders.size());
678 for (LocationProviderInterface provider : mProviders) {
679 String name = provider.getName();
680 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700681 continue;
682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 out.add(name);
684 }
685 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700686
687 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 return out;
689 }
690
Mike Lockwood03ca2162010-04-01 08:10:09 -0700691 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700692 * Return all providers by name, that match criteria and are optionally
693 * enabled.
694 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700695 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700696 @Override
697 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700698 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700699 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700700 out = new ArrayList<String>(mProviders.size());
701 for (LocationProviderInterface provider : mProviders) {
702 String name = provider.getName();
703 if (LocationManager.FUSED_PROVIDER.equals(name)) {
704 continue;
705 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700706 if (isAllowedProviderSafe(name)) {
707 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
708 continue;
709 }
710 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
711 name, provider.getProperties(), criteria)) {
712 continue;
713 }
714 out.add(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700715 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700716 }
717 }
718
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700719 if (D) Log.d(TAG, "getProviders()=" + out);
720 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700721 }
722
723 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700724 * Return the name of the best provider given a Criteria object.
725 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700726 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700727 * has been deprecated as well. So this method now uses
728 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700729 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700730 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700731 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700732 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700733
734 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700735 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700736 result = pickBest(providers);
737 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
738 return result;
739 }
740 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700741 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700742 result = pickBest(providers);
743 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
744 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700745 }
746
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700747 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700748 return null;
749 }
750
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700751 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700752 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700753 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700754 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
755 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700756 } else {
757 return providers.get(0);
758 }
759 }
760
Nick Pellye0fd6932012-07-11 10:26:13 -0700761 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700762 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700763 checkPermission();
764
Mike Lockwood03ca2162010-04-01 08:10:09 -0700765 LocationProviderInterface p = mProvidersByName.get(provider);
766 if (p == null) {
767 throw new IllegalArgumentException("provider=" + provider);
768 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700769
770 boolean result = LocationProvider.propertiesMeetCriteria(
771 p.getName(), p.getProperties(), criteria);
772 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
773 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700774 }
775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700777 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400778 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500779 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 boolean isEnabled = p.isEnabled();
781 String name = p.getName();
782 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 if (isEnabled && !shouldBeEnabled) {
784 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700785 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 } else if (!isEnabled && shouldBeEnabled) {
787 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700788 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700790 }
791 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700792 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
793 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 }
795 }
796
797 private void updateProviderListenersLocked(String provider, boolean enabled) {
798 int listeners = 0;
799
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500800 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700801 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802
803 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
806 if (records != null) {
807 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700808 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 UpdateRecord record = records.get(i);
810 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700811 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
812 if (deadReceivers == null) {
813 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 }
Simon Schoar46866572009-06-10 21:12:10 +0200815 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 }
817 listeners++;
818 }
819 }
820
821 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700822 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 removeUpdatesLocked(deadReceivers.get(i));
824 }
825 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 if (enabled) {
828 p.enable();
829 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700830 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 }
832 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 }
836
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700837 private void applyRequirementsLocked(String provider) {
838 LocationProviderInterface p = mProvidersByName.get(provider);
839 if (p == null) return;
840
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700842 WorkSource worksource = new WorkSource();
843 ProviderRequest providerRequest = new ProviderRequest();
844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700846 for (UpdateRecord record : records) {
847 LocationRequest locationRequest = record.mRequest;
848
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700849 providerRequest.locationRequests.add(locationRequest);
850 if (locationRequest.getInterval() < providerRequest.interval) {
851 providerRequest.reportLocation = true;
852 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700853 }
854 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700855
856 if (providerRequest.reportLocation) {
857 // calculate who to blame for power
858 // This is somewhat arbitrary. We pick a threshold interval
859 // that is slightly higher that the minimum interval, and
860 // spread the blame across all applications with a request
861 // under that threshold.
862 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
863 for (UpdateRecord record : records) {
864 LocationRequest locationRequest = record.mRequest;
865 if (locationRequest.getInterval() <= thresholdInterval) {
866 worksource.add(record.mReceiver.mUid);
867 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700868 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869 }
870 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700871
872 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
873 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 }
875
876 private class UpdateRecord {
877 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700878 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400880 Location mLastFixBroadcast;
881 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882
883 /**
884 * Note: must be constructed with lock held.
885 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700886 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700888 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890
891 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
892 if (records == null) {
893 records = new ArrayList<UpdateRecord>();
894 mRecordsByProvider.put(provider, records);
895 }
896 if (!records.contains(this)) {
897 records.add(this);
898 }
899 }
900
901 /**
902 * Method to be called when a record will no longer be used. Calling this multiple times
903 * must have the same effect as calling it once.
904 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700905 void disposeLocked(boolean removeReceiver) {
906 // remove from mRecordsByProvider
907 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
908 if (globalRecords != null) {
909 globalRecords.remove(this);
910 }
911
912 if (!removeReceiver) return; // the caller will handle the rest
913
914 // remove from Receiver#mUpdateRecords
915 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
916 if (receiverRecords != null) {
917 receiverRecords.remove(this.mProvider);
918
919 // and also remove the Receiver if it has no more update records
920 if (removeReceiver && receiverRecords.size() == 0) {
921 removeUpdatesLocked(mReceiver);
922 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 }
925
926 @Override
927 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700928 StringBuilder s = new StringBuilder();
929 s.append("UpdateRecord[");
930 s.append(mProvider);
931 s.append(' ').append(mReceiver.mPackageName).append('(');
932 s.append(mReceiver.mUid).append(')');
933 s.append(' ').append(mRequest);
934 s.append(']');
935 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 }
938
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700939 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400940 IBinder binder = listener.asBinder();
941 Receiver receiver = mReceivers.get(binder);
942 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700943 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400944 mReceivers.put(binder, receiver);
945
946 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700947 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400948 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800949 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400950 return null;
951 }
952 }
953 return receiver;
954 }
955
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700956 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400957 Receiver receiver = mReceivers.get(intent);
958 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700959 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400960 mReceivers.put(intent, receiver);
961 }
962 return receiver;
963 }
964
Victoria Lease09016ab2012-09-16 12:33:15 -0700965 private boolean isProviderAllowedByCoarsePermission(String provider) {
966 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
967 return true;
968 }
969 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
970 return true;
971 }
972 if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
973 return true;
974 }
975 return false;
976 }
977
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700978 private String checkPermissionAndRequest(LocationRequest request) {
979 String perm = checkPermission();
980
981 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Victoria Lease09016ab2012-09-16 12:33:15 -0700982 if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
983 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
984 }
985 switch (request.getQuality()) {
986 case LocationRequest.ACCURACY_FINE:
987 request.setQuality(LocationRequest.ACCURACY_BLOCK);
988 break;
989 case LocationRequest.POWER_HIGH:
990 request.setQuality(LocationRequest.POWER_LOW);
991 break;
992 }
993 // throttle
994 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
995 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
996 }
997 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
998 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
999 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001000 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001001 // make getFastestInterval() the minimum of interval and fastest interval
1002 if (request.getFastestInterval() > request.getInterval()) {
1003 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001004 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001005 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001006 }
1007
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001008 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001009 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001010 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001011 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001012 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001013 String[] packages = mPackageManager.getPackagesForUid(uid);
1014 if (packages == null) {
1015 throw new SecurityException("invalid UID " + uid);
1016 }
1017 for (String pkg : packages) {
1018 if (packageName.equals(pkg)) return;
1019 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001020 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001021 }
1022
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001023 private void checkPendingIntent(PendingIntent intent) {
1024 if (intent == null) {
1025 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001026 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001027 }
1028
1029 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1030 int pid, int uid, String packageName) {
1031 if (intent == null && listener == null) {
1032 throw new IllegalArgumentException("need eiter listener or intent");
1033 } else if (intent != null && listener != null) {
1034 throw new IllegalArgumentException("cannot register both listener and intent");
1035 } else if (intent != null) {
1036 checkPendingIntent(intent);
1037 return getReceiver(intent, pid, uid, packageName);
1038 } else {
1039 return getReceiver(listener, pid, uid, packageName);
1040 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001041 }
1042
Nick Pellye0fd6932012-07-11 10:26:13 -07001043 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001044 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1045 PendingIntent intent, String packageName) {
1046 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1047 checkPackageName(packageName);
1048 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001050 final int pid = Binder.getCallingPid();
1051 final int uid = Binder.getCallingUid();
1052 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001054 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 long identity = Binder.clearCallingIdentity();
1056 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001057 synchronized (mLock) {
1058 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001059 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 } finally {
1061 Binder.restoreCallingIdentity(identity);
1062 }
1063 }
1064
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001065 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1066 int pid, int uid, String packageName) {
1067 // Figure out the provider. Either its explicitly request (legacy use cases), or
1068 // use the fused provider
1069 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1070 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001071 if (name == null) {
1072 throw new IllegalArgumentException("provider name must not be null");
1073 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001074 LocationProviderInterface provider = mProvidersByName.get(name);
1075 if (provider == null) {
1076 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1077 }
1078
1079 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1080 name + " " + request + " from " + packageName + "(" + uid + ")");
1081
1082 UpdateRecord record = new UpdateRecord(name, request, receiver);
1083 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1084 if (oldRecord != null) {
1085 oldRecord.disposeLocked(false);
1086 }
1087
1088 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1089 if (isProviderEnabled) {
1090 applyRequirementsLocked(name);
1091 } else {
1092 // Notify the listener that updates are currently disabled
1093 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 }
1095 }
1096
Nick Pellye0fd6932012-07-11 10:26:13 -07001097 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001098 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1099 String packageName) {
1100 checkPackageName(packageName);
1101 checkPermission();
1102 final int pid = Binder.getCallingPid();
1103 final int uid = Binder.getCallingUid();
1104 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1105
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001106 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001107 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001109 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001110 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001112 } finally {
1113 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 }
1115 }
1116
1117 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001118 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1119
1120 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1121 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1122 synchronized (receiver) {
1123 if (receiver.mPendingBroadcasts > 0) {
1124 decrementPendingBroadcasts();
1125 receiver.mPendingBroadcasts = 0;
1126 }
1127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 }
1129
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001130 // Record which providers were associated with this listener
1131 HashSet<String> providers = new HashSet<String>();
1132 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1133 if (oldRecords != null) {
1134 // Call dispose() on the obsolete update records.
1135 for (UpdateRecord record : oldRecords.values()) {
1136 record.disposeLocked(false);
1137 }
1138 // Accumulate providers
1139 providers.addAll(oldRecords.keySet());
1140 }
1141
1142 // update provider
1143 for (String provider : providers) {
1144 // If provider is already disabled, don't need to do anything
1145 if (!isAllowedBySettingsLocked(provider)) {
1146 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 }
1148
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001149 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 }
1151 }
1152
Nick Pellye0fd6932012-07-11 10:26:13 -07001153 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001154 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001155 if (D) Log.d(TAG, "getLastLocation: " + request);
1156 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1157 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001158 checkPackageName(packageName);
1159
1160 if (mBlacklist.isBlacklisted(packageName)) {
1161 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1162 packageName);
1163 return null;
1164 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001165
1166 synchronized (mLock) {
1167 // Figure out the provider. Either its explicitly request (deprecated API's),
1168 // or use the fused provider
1169 String name = request.getProvider();
1170 if (name == null) name = LocationManager.FUSED_PROVIDER;
1171 LocationProviderInterface provider = mProvidersByName.get(name);
1172 if (provider == null) return null;
1173
1174 if (!isAllowedBySettingsLocked(name)) return null;
1175
1176 Location location = mLastLocation.get(name);
Victoria Lease09016ab2012-09-16 12:33:15 -07001177 if (location == null) {
1178 return null;
1179 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001180 if (ACCESS_FINE_LOCATION.equals(perm)) {
1181 return location;
1182 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001183 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1184 if (noGPSLocation != null) {
1185 return mLocationFudger.getOrCreate(noGPSLocation);
1186 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001187 }
1188 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001189 return null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001190 }
1191
1192 @Override
1193 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1194 String packageName) {
1195 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001196 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001197 checkPermissionAndRequest(request);
1198 checkPendingIntent(intent);
1199 checkPackageName(packageName);
1200
1201 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1202
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001203 // geo-fence manager uses the public location API, need to clear identity
1204 int uid = Binder.getCallingUid();
1205 long identity = Binder.clearCallingIdentity();
1206 try {
1207 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1208 } finally {
1209 Binder.restoreCallingIdentity(identity);
1210 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001211 }
1212
1213 @Override
1214 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001215 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001216 checkPendingIntent(intent);
1217 checkPackageName(packageName);
1218
1219 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1220
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001221 // geo-fence manager uses the public location API, need to clear identity
1222 long identity = Binder.clearCallingIdentity();
1223 try {
1224 mGeofenceManager.removeFence(geofence, intent);
1225 } finally {
1226 Binder.restoreCallingIdentity(identity);
1227 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001228 }
1229
1230
1231 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001233 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 return false;
1235 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001236 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 PackageManager.PERMISSION_GRANTED) {
1238 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1239 }
1240
1241 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001242 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001244 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001245 return false;
1246 }
1247 return true;
1248 }
1249
Nick Pellye0fd6932012-07-11 10:26:13 -07001250 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001252 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001253 try {
1254 mGpsStatusProvider.removeGpsStatusListener(listener);
1255 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001256 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001257 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 }
1259 }
1260
Nick Pellye0fd6932012-07-11 10:26:13 -07001261 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001263 if (provider == null) {
1264 // throw NullPointerException to remain compatible with previous implementation
1265 throw new NullPointerException();
1266 }
1267
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001268 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001270 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 != PackageManager.PERMISSION_GRANTED)) {
1272 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1273 }
1274
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001275 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001276 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001277 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001278
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001279 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 }
1281 }
1282
Nick Pellye0fd6932012-07-11 10:26:13 -07001283 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001285 if (Binder.getCallingUid() != Process.myUid()) {
1286 throw new SecurityException(
1287 "calling sendNiResponse from outside of the system is not allowed");
1288 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001289 try {
1290 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001291 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001292 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001293 return false;
1294 }
1295 }
1296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001298 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001299 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300 * accessed by the caller
1301 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001302 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001303 public ProviderProperties getProviderProperties(String provider) {
1304 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001306 LocationProviderInterface p;
1307 synchronized (mLock) {
1308 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 }
1310
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001311 if (p == null) return null;
1312 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 }
1314
Nick Pellye0fd6932012-07-11 10:26:13 -07001315 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 public boolean isProviderEnabled(String provider) {
Victoria Leasef429921e2012-10-04 08:01:19 -07001317 String perms = checkPermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001318 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
Victoria Leasef429921e2012-10-04 08:01:19 -07001319 if (ACCESS_COARSE_LOCATION.equals(perms) &&
1320 !isProviderAllowedByCoarsePermission(provider)) {
1321 throw new SecurityException("The \"" + provider +
1322 "\" provider requires ACCESS_FINE_LOCATION permission");
1323 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324
1325 synchronized (mLock) {
1326 LocationProviderInterface p = mProvidersByName.get(provider);
1327 if (p == null) return false;
1328
1329 return isAllowedBySettingsLocked(provider);
1330 }
1331 }
1332
1333 private void checkCallerIsProvider() {
1334 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1335 == PackageManager.PERMISSION_GRANTED) {
1336 return;
1337 }
1338
1339 // Previously we only used the INSTALL_LOCATION_PROVIDER
1340 // check. But that is system or signature
1341 // protection level which is not flexible enough for
1342 // providers installed oustide the system image. So
1343 // also allow providers with a UID matching the
1344 // currently bound package name
1345
1346 int uid = Binder.getCallingUid();
1347
1348 if (mGeocodeProvider != null) {
1349 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1350 }
1351 for (LocationProviderProxy proxy : mProxyProviders) {
1352 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1353 }
1354 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1355 "or UID of a currently bound location provider");
1356 }
1357
1358 private boolean doesPackageHaveUid(int uid, String packageName) {
1359 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 return false;
1361 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001362 try {
1363 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1364 if (appInfo.uid != uid) {
1365 return false;
1366 }
1367 } catch (NameNotFoundException e) {
1368 return false;
1369 }
1370 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 }
1372
Nick Pellye0fd6932012-07-11 10:26:13 -07001373 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001374 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001375 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001376
Nick Pelly2eeeec22012-07-18 13:13:37 -07001377 if (!location.isComplete()) {
1378 Log.w(TAG, "Dropping incomplete location: " + location);
1379 return;
1380 }
1381
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001382 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1383 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001384 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001385 mLocationHandler.sendMessageAtFrontOfQueue(m);
1386 }
1387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388
1389 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1390 // Always broadcast the first update
1391 if (lastLoc == null) {
1392 return true;
1393 }
1394
Nick Pellyf1be6862012-05-15 10:53:42 -07001395 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001396 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001397 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001398 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 return false;
1400 }
1401
1402 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001403 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 if (minDistance > 0.0) {
1405 if (loc.distanceTo(lastLoc) <= minDistance) {
1406 return false;
1407 }
1408 }
1409
1410 return true;
1411 }
1412
Mike Lockwooda4903f22010-02-17 06:42:23 -05001413 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001414 if (D) Log.d(TAG, "incoming location: " + location);
1415
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001416 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001417 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418
Laurent Tu60ec50a2012-10-04 17:00:10 -07001419 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001420 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001421 if (p == null) return;
1422
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001423 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001424 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1425 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001426 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001427 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001428 lastLocation = new Location(provider);
1429 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001430 } else {
1431 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1432 if (noGPSLocation == null && lastNoGPSLocation != null) {
1433 // New location has no no-GPS location: adopt last no-GPS location. This is set
1434 // directly into location because we do not want to notify COARSE clients.
1435 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1436 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001437 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001438 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439
Laurent Tu60ec50a2012-10-04 17:00:10 -07001440 // Skip if there are no UpdateRecords for this provider.
1441 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1442 if (records == null || records.size() == 0) return;
1443
Victoria Lease09016ab2012-09-16 12:33:15 -07001444 // Fetch coarse location
1445 Location coarseLocation = null;
1446 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1447 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1448 }
1449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450 // Fetch latest status update time
1451 long newStatusUpdateTime = p.getStatusUpdateTime();
1452
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001453 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 Bundle extras = new Bundle();
1455 int status = p.getStatus(extras);
1456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001458 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001461 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001463 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001464
1465 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1466 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1467 receiver.mPackageName);
1468 continue;
1469 }
1470
Victoria Lease09016ab2012-09-16 12:33:15 -07001471 Location notifyLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001472 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001473 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001474 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001475 notifyLocation = coarseLocation; // use coarse location if available
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001476 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001477 if (notifyLocation != null) {
1478 Location lastLoc = r.mLastFixBroadcast;
1479 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1480 if (lastLoc == null) {
1481 lastLoc = new Location(notifyLocation);
1482 r.mLastFixBroadcast = lastLoc;
1483 } else {
1484 lastLoc.set(notifyLocation);
1485 }
1486 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1487 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1488 receiverDead = true;
1489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 }
1491 }
1492
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001493 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001495 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001497 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001499 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001500 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001501 }
1502 }
1503
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001504 // track expired records
1505 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1506 if (deadUpdateRecords == null) {
1507 deadUpdateRecords = new ArrayList<UpdateRecord>();
1508 }
1509 deadUpdateRecords.add(r);
1510 }
1511 // track dead receivers
1512 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001513 if (deadReceivers == null) {
1514 deadReceivers = new ArrayList<Receiver>();
1515 }
1516 if (!deadReceivers.contains(receiver)) {
1517 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 }
1519 }
1520 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001521
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001522 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001524 for (Receiver receiver : deadReceivers) {
1525 removeUpdatesLocked(receiver);
1526 }
1527 }
1528 if (deadUpdateRecords != null) {
1529 for (UpdateRecord r : deadUpdateRecords) {
1530 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531 }
1532 }
1533 }
1534
1535 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 @Override
1537 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001538 switch (msg.what) {
1539 case MSG_LOCATION_CHANGED:
1540 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1541 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 }
1543 }
1544 }
1545
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001546 private void handleLocationChanged(Location location, boolean passive) {
1547 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001548
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001549 if (!passive) {
1550 // notify passive provider of the new location
1551 mPassiveProvider.updateLocation(location);
1552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001554 synchronized (mLock) {
1555 if (isAllowedBySettingsLocked(provider)) {
1556 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560
Mike Lockwoode97ae402010-09-29 15:23:46 -04001561 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1562 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001563 public void onPackageDisappeared(String packageName, int reason) {
1564 // remove all receivers associated with this package name
1565 synchronized (mLock) {
1566 ArrayList<Receiver> deadReceivers = null;
1567
1568 for (Receiver receiver : mReceivers.values()) {
1569 if (receiver.mPackageName.equals(packageName)) {
1570 if (deadReceivers == null) {
1571 deadReceivers = new ArrayList<Receiver>();
1572 }
1573 deadReceivers.add(receiver);
1574 }
1575 }
1576
1577 // perform removal outside of mReceivers loop
1578 if (deadReceivers != null) {
1579 for (Receiver receiver : deadReceivers) {
1580 removeUpdatesLocked(receiver);
1581 }
1582 }
1583 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001584 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001585 };
1586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 // Wake locks
1588
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001589 private void incrementPendingBroadcasts() {
1590 synchronized (mWakeLock) {
1591 if (mPendingBroadcasts++ == 0) {
1592 try {
1593 mWakeLock.acquire();
1594 log("Acquired wakelock");
1595 } catch (Exception e) {
1596 // This is to catch a runtime exception thrown when we try to release an
1597 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001598 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001599 }
1600 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001601 }
1602 }
1603
1604 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001605 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001606 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001607 try {
1608 // Release wake lock
1609 if (mWakeLock.isHeld()) {
1610 mWakeLock.release();
1611 log("Released wakelock");
1612 } else {
1613 log("Can't release wakelock again!");
1614 }
1615 } catch (Exception e) {
1616 // This is to catch a runtime exception thrown when we try to release an
1617 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001618 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001619 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001620 }
1621 }
1622 }
1623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 // Geocoder
1625
Nick Pellye0fd6932012-07-11 10:26:13 -07001626 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001627 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001628 return mGeocodeProvider != null;
1629 }
1630
Nick Pellye0fd6932012-07-11 10:26:13 -07001631 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001633 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001634 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001635 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1636 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001637 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001638 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 }
1640
Mike Lockwooda55c3212009-04-15 11:10:11 -04001641
Nick Pellye0fd6932012-07-11 10:26:13 -07001642 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001644 double lowerLeftLatitude, double lowerLeftLongitude,
1645 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001646 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001647
1648 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001649 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1650 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1651 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001653 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 }
1655
1656 // Mock Providers
1657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 private void checkMockPermissionsSafe() {
1659 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1660 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1661 if (!allowMocks) {
1662 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1663 }
1664
1665 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1666 PackageManager.PERMISSION_GRANTED) {
1667 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 }
1670
Nick Pellye0fd6932012-07-11 10:26:13 -07001671 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001672 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 checkMockPermissionsSafe();
1674
Mike Lockwooda4903f22010-02-17 06:42:23 -05001675 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1676 throw new IllegalArgumentException("Cannot mock the passive location provider");
1677 }
1678
Mike Lockwood86328a92009-10-23 08:38:25 -04001679 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001680 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001681 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001682 // remove the real provider if we are replacing GPS or network provider
1683 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001684 || LocationManager.NETWORK_PROVIDER.equals(name)
1685 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001686 LocationProviderInterface p = mProvidersByName.get(name);
1687 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001688 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001689 }
1690 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001691 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1693 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001694 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001695 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001696 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 updateProvidersLocked();
1698 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001699 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 }
1701
Nick Pellye0fd6932012-07-11 10:26:13 -07001702 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 public void removeTestProvider(String provider) {
1704 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001705 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001706 MockProvider mockProvider = mMockProviders.get(provider);
1707 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1709 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001710 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001711 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001712 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001713
1714 // reinstate real provider if available
1715 LocationProviderInterface realProvider = mRealProviders.get(provider);
1716 if (realProvider != null) {
1717 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001718 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001719 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001721 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 }
1723 }
1724
Nick Pellye0fd6932012-07-11 10:26:13 -07001725 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 public void setTestProviderLocation(String provider, Location loc) {
1727 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001728 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001729 MockProvider mockProvider = mMockProviders.get(provider);
1730 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1732 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001733 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1734 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001735 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001736 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 }
1738 }
1739
Nick Pellye0fd6932012-07-11 10:26:13 -07001740 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 public void clearTestProviderLocation(String provider) {
1742 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001743 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001744 MockProvider mockProvider = mMockProviders.get(provider);
1745 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1747 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001748 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001749 }
1750 }
1751
Nick Pellye0fd6932012-07-11 10:26:13 -07001752 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 public void setTestProviderEnabled(String provider, boolean enabled) {
1754 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001755 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001756 MockProvider mockProvider = mMockProviders.get(provider);
1757 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1759 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001760 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001762 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 mEnabledProviders.add(provider);
1764 mDisabledProviders.remove(provider);
1765 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001766 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 mEnabledProviders.remove(provider);
1768 mDisabledProviders.add(provider);
1769 }
1770 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001771 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 }
1773 }
1774
Nick Pellye0fd6932012-07-11 10:26:13 -07001775 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776 public void clearTestProviderEnabled(String provider) {
1777 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001778 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001779 MockProvider mockProvider = mMockProviders.get(provider);
1780 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1782 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001783 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 mEnabledProviders.remove(provider);
1785 mDisabledProviders.remove(provider);
1786 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001787 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001788 }
1789 }
1790
Nick Pellye0fd6932012-07-11 10:26:13 -07001791 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1793 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001794 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001795 MockProvider mockProvider = mMockProviders.get(provider);
1796 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1798 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001799 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800 }
1801 }
1802
Nick Pellye0fd6932012-07-11 10:26:13 -07001803 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 public void clearTestProviderStatus(String provider) {
1805 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001806 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001807 MockProvider mockProvider = mMockProviders.get(provider);
1808 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1810 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001811 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 }
1813 }
1814
1815 private void log(String log) {
1816 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001817 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 }
1819 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001820
1821 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1823 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1824 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001825 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 + Binder.getCallingPid()
1827 + ", uid=" + Binder.getCallingUid());
1828 return;
1829 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001830
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001831 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001834 for (Receiver receiver : mReceivers.values()) {
1835 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001838 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1839 pw.println(" " + entry.getKey() + ":");
1840 for (UpdateRecord record : entry.getValue()) {
1841 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 }
1843 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001844 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001845 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1846 String provider = entry.getKey();
1847 Location location = entry.getValue();
1848 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001850
Nick Pellye0fd6932012-07-11 10:26:13 -07001851 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001852
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 if (mEnabledProviders.size() > 0) {
1854 pw.println(" Enabled Providers:");
1855 for (String i : mEnabledProviders) {
1856 pw.println(" " + i);
1857 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859 }
1860 if (mDisabledProviders.size() > 0) {
1861 pw.println(" Disabled Providers:");
1862 for (String i : mDisabledProviders) {
1863 pw.println(" " + i);
1864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001866 pw.append(" ");
1867 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001868 if (mMockProviders.size() > 0) {
1869 pw.println(" Mock Providers:");
1870 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001871 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 }
1873 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001874
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001875 pw.append(" fudger: ");
1876 mLocationFudger.dump(fd, pw, args);
1877
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001878 if (args.length > 0 && "short".equals(args[0])) {
1879 return;
1880 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001881 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001882 pw.print(provider.getName() + " Internal State");
1883 if (provider instanceof LocationProviderProxy) {
1884 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1885 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001886 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001887 pw.println(":");
1888 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001889 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 }
1891 }
1892}