blob: c5016e6bb3e89a92924aff5b4b74965daae85656 [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 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700229 }, UserHandle.USER_ALL);
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,
Victoria Leaseb711d572012-10-02 13:14:11 -0700292 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700293 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,
Victoria Leaseb711d572012-10-02 13:14:11 -0700306 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700307 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
Victoria Leaseb711d572012-10-02 13:14:11 -0700318 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
319 mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700320 if (mGeocodeProvider == null) {
321 Slog.e(TAG, "no geocoder provider found");
322 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700323 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700326 * Called when the device's active user changes.
327 * @param userId the new active user's UserId
328 */
329 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700330 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700331 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700332 mLastLocation.clear();
333 for (LocationProviderInterface p : mProviders) {
334 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
335 p.switchUser(userId);
336 }
Victoria Lease38389b62012-09-30 11:44:22 -0700337 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700338 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700339 }
340 }
341
342 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
344 * location updates.
345 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700346 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700347 final int mUid; // uid of receiver
348 final int mPid; // pid of receiver
349 final String mPackageName; // package name of receiver
350 final String mPermission; // best permission that receiver has
351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 final ILocationListener mListener;
353 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700355
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400356 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700357
Mike Lockwood48f17512009-04-23 09:12:08 -0700358 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700360 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
361 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700364 if (listener != null) {
365 mKey = listener.asBinder();
366 } else {
367 mKey = intent;
368 }
369 mPermission = checkPermission();
370 mUid = uid;
371 mPid = pid;
372 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 }
374
375 @Override
376 public boolean equals(Object otherObj) {
377 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700378 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
380 return false;
381 }
382
383 @Override
384 public int hashCode() {
385 return mKey.hashCode();
386 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 @Override
389 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700390 StringBuilder s = new StringBuilder();
391 s.append("Reciever[");
392 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700394 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700396 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700398 for (String p : mUpdateRecords.keySet()) {
399 s.append(" ").append(mUpdateRecords.get(p).toString());
400 }
401 s.append("]");
402 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 }
404
405 public boolean isListener() {
406 return mListener != null;
407 }
408
409 public boolean isPendingIntent() {
410 return mPendingIntent != null;
411 }
412
413 public ILocationListener getListener() {
414 if (mListener != null) {
415 return mListener;
416 }
417 throw new IllegalStateException("Request for non-existent listener");
418 }
419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
421 if (mListener != null) {
422 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700423 synchronized (this) {
424 // synchronize to ensure incrementPendingBroadcastsLocked()
425 // is called before decrementPendingBroadcasts()
426 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700427 // call this after broadcasting so we do not increment
428 // if we throw an exeption.
429 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 } catch (RemoteException e) {
432 return false;
433 }
434 } else {
435 Intent statusChanged = new Intent();
436 statusChanged.putExtras(extras);
437 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
438 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700439 synchronized (this) {
440 // synchronize to ensure incrementPendingBroadcastsLocked()
441 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700442 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700443 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700444 // call this after broadcasting so we do not increment
445 // if we throw an exeption.
446 incrementPendingBroadcastsLocked();
447 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 } catch (PendingIntent.CanceledException e) {
449 return false;
450 }
451 }
452 return true;
453 }
454
455 public boolean callLocationChangedLocked(Location location) {
456 if (mListener != null) {
457 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700458 synchronized (this) {
459 // synchronize to ensure incrementPendingBroadcastsLocked()
460 // is called before decrementPendingBroadcasts()
461 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700462 // call this after broadcasting so we do not increment
463 // if we throw an exeption.
464 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700465 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 } catch (RemoteException e) {
467 return false;
468 }
469 } else {
470 Intent locationChanged = new Intent();
471 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
472 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700473 synchronized (this) {
474 // synchronize to ensure incrementPendingBroadcastsLocked()
475 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700476 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700477 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700478 // call this after broadcasting so we do not increment
479 // if we throw an exeption.
480 incrementPendingBroadcastsLocked();
481 }
482 } catch (PendingIntent.CanceledException e) {
483 return false;
484 }
485 }
486 return true;
487 }
488
489 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
490 if (mListener != null) {
491 try {
492 synchronized (this) {
493 // synchronize to ensure incrementPendingBroadcastsLocked()
494 // is called before decrementPendingBroadcasts()
495 if (enabled) {
496 mListener.onProviderEnabled(provider);
497 } else {
498 mListener.onProviderDisabled(provider);
499 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700500 // call this after broadcasting so we do not increment
501 // if we throw an exeption.
502 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700503 }
504 } catch (RemoteException e) {
505 return false;
506 }
507 } else {
508 Intent providerIntent = new Intent();
509 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
510 try {
511 synchronized (this) {
512 // synchronize to ensure incrementPendingBroadcastsLocked()
513 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700514 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700515 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700516 // call this after broadcasting so we do not increment
517 // if we throw an exeption.
518 incrementPendingBroadcastsLocked();
519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 } catch (PendingIntent.CanceledException e) {
521 return false;
522 }
523 }
524 return true;
525 }
526
Nick Pellyf1be6862012-05-15 10:53:42 -0700527 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700529 if (D) Log.d(TAG, "Location listener died");
530
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400531 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 removeUpdatesLocked(this);
533 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700534 synchronized (this) {
535 if (mPendingBroadcasts > 0) {
536 LocationManagerService.this.decrementPendingBroadcasts();
537 mPendingBroadcasts = 0;
538 }
539 }
540 }
541
Nick Pellye0fd6932012-07-11 10:26:13 -0700542 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700543 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
544 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400545 synchronized (this) {
546 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700547 }
548 }
549
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400550 // this must be called while synchronized by caller in a synchronized block
551 // containing the sending of the broadcaset
552 private void incrementPendingBroadcastsLocked() {
553 if (mPendingBroadcasts++ == 0) {
554 LocationManagerService.this.incrementPendingBroadcasts();
555 }
556 }
557
558 private void decrementPendingBroadcastsLocked() {
559 if (--mPendingBroadcasts == 0) {
560 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700561 }
562 }
563 }
564
Nick Pellye0fd6932012-07-11 10:26:13 -0700565 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700566 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400567 //Do not use getReceiver here as that will add the ILocationListener to
568 //the receiver list if it is not found. If it is not found then the
569 //LocationListener was removed when it had a pending broadcast and should
570 //not be added back.
571 IBinder binder = listener.asBinder();
572 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700573 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400574 synchronized (receiver) {
575 // so wakelock calls will succeed
576 long identity = Binder.clearCallingIdentity();
577 receiver.decrementPendingBroadcastsLocked();
578 Binder.restoreCallingIdentity(identity);
579 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 }
581 }
582
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700583 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400584 mProviders.add(provider);
585 mProvidersByName.put(provider.getName(), provider);
586 }
587
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700588 private void removeProviderLocked(LocationProviderInterface provider) {
589 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400590 mProviders.remove(provider);
591 mProvidersByName.remove(provider.getName());
592 }
593
Mike Lockwood3d12b512009-04-21 23:25:35 -0700594
Victoria Leaseb711d572012-10-02 13:14:11 -0700595 private boolean isAllowedBySettingsLocked(String provider, int userId) {
596 if (userId != mCurrentUserId) {
597 return false;
598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 if (mEnabledProviders.contains(provider)) {
600 return true;
601 }
602 if (mDisabledProviders.contains(provider)) {
603 return false;
604 }
605 // Use system settings
606 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607
Victoria Leaseb711d572012-10-02 13:14:11 -0700608 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 }
610
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700611 /**
612 * Throw SecurityException if caller has neither COARSE or FINE.
613 * Otherwise, return the best permission.
614 */
615 private String checkPermission() {
616 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
617 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700618 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700619 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
620 PackageManager.PERMISSION_GRANTED) {
621 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700623
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700624 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
Victoria Lease4fab68b2012-09-13 13:20:59 -0700625 " ACCESS_FINE_LOCATION permission");
626 }
627
628 /**
629 * Throw SecurityException if caller lacks permission to use Geofences.
630 */
631 private void checkGeofencePermission() {
632 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
633 PackageManager.PERMISSION_GRANTED) {
634 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
635 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 }
637
Victoria Lease8dbb6342012-09-21 16:55:53 -0700638 private boolean isAllowedProviderSafe(String provider) {
639 if (LocationManager.GPS_PROVIDER.equals(provider) ||
640 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
641 // gps and passive providers require FINE permission
642 return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
643 == PackageManager.PERMISSION_GRANTED;
644 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
645 LocationManager.FUSED_PROVIDER.equals(provider)) {
646 // network and fused providers are ok with COARSE or FINE
647 return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
648 == PackageManager.PERMISSION_GRANTED) ||
649 (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
650 == PackageManager.PERMISSION_GRANTED);
Laurent Tu941221c2012-10-04 14:21:52 -0700651 } else {
652 // mock providers
653 LocationProviderInterface lp = mMockProviders.get(provider);
654 if (lp != null) {
655 ProviderProperties properties = lp.getProperties();
656 if (properties != null) {
657 if (properties.mRequiresSatellite) {
658 // provider requiring satellites require FINE permission
659 return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
660 == PackageManager.PERMISSION_GRANTED;
661 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
662 // provider requiring network and or cell require COARSE or FINE
663 return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
664 == PackageManager.PERMISSION_GRANTED) ||
665 (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
666 == PackageManager.PERMISSION_GRANTED);
667 }
668 }
669 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700670 }
Laurent Tu941221c2012-10-04 14:21:52 -0700671
Victoria Lease8dbb6342012-09-21 16:55:53 -0700672 return false;
673 }
674
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700675 /**
676 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700677 * fused, also including ones that are not permitted to
678 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700679 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700680 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700682 ArrayList<String> out;
683 synchronized (mLock) {
684 out = new ArrayList<String>(mProviders.size());
685 for (LocationProviderInterface provider : mProviders) {
686 String name = provider.getName();
687 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700688 continue;
689 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 out.add(name);
691 }
692 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700693
694 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 return out;
696 }
697
Mike Lockwood03ca2162010-04-01 08:10:09 -0700698 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700699 * Return all providers by name, that match criteria and are optionally
700 * enabled.
701 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700702 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700703 @Override
704 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700705 ArrayList<String> out;
Victoria Leaseb711d572012-10-02 13:14:11 -0700706 int callingUserId = UserHandle.getCallingUserId();
707 long identity = Binder.clearCallingIdentity();
708 try {
709 synchronized (mLock) {
710 out = new ArrayList<String>(mProviders.size());
711 for (LocationProviderInterface provider : mProviders) {
712 String name = provider.getName();
713 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700714 continue;
715 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700716 if (isAllowedProviderSafe(name)) {
717 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
718 continue;
719 }
720 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
721 name, provider.getProperties(), criteria)) {
722 continue;
723 }
724 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700725 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700726 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700727 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700728 } finally {
729 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700730 }
731
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700732 if (D) Log.d(TAG, "getProviders()=" + out);
733 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700734 }
735
736 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700737 * Return the name of the best provider given a Criteria object.
738 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700739 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700740 * has been deprecated as well. So this method now uses
741 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700742 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700743 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700744 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700745 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700746
747 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700748 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700749 result = pickBest(providers);
750 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
751 return result;
752 }
753 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700754 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700755 result = pickBest(providers);
756 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
757 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700758 }
759
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700760 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700761 return null;
762 }
763
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700764 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700765 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700766 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700767 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
768 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700769 } else {
770 return providers.get(0);
771 }
772 }
773
Nick Pellye0fd6932012-07-11 10:26:13 -0700774 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700775 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700776 checkPermission();
777
Mike Lockwood03ca2162010-04-01 08:10:09 -0700778 LocationProviderInterface p = mProvidersByName.get(provider);
779 if (p == null) {
780 throw new IllegalArgumentException("provider=" + provider);
781 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700782
783 boolean result = LocationProvider.propertiesMeetCriteria(
784 p.getName(), p.getProperties(), criteria);
785 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
786 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700787 }
788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700790 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400791 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500792 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 boolean isEnabled = p.isEnabled();
794 String name = p.getName();
Victoria Leaseb711d572012-10-02 13:14:11 -0700795 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700797 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700798 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700800 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700801 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700803 }
804 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700805 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
806 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
808 }
809
Victoria Leaseb711d572012-10-02 13:14:11 -0700810 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 int listeners = 0;
812
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500813 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700814 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815
816 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
819 if (records != null) {
820 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700821 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 UpdateRecord record = records.get(i);
Victoria Leaseb711d572012-10-02 13:14:11 -0700823 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
824 // Sends a notification message to the receiver
825 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
826 if (deadReceivers == null) {
827 deadReceivers = new ArrayList<Receiver>();
828 }
829 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700831 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 }
834 }
835
836 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700837 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 removeUpdatesLocked(deadReceivers.get(i));
839 }
840 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 if (enabled) {
843 p.enable();
844 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700845 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 }
847 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 }
851
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700852 private void applyRequirementsLocked(String provider) {
853 LocationProviderInterface p = mProvidersByName.get(provider);
854 if (p == null) return;
855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700857 WorkSource worksource = new WorkSource();
858 ProviderRequest providerRequest = new ProviderRequest();
859
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700861 for (UpdateRecord record : records) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700862 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
863 LocationRequest locationRequest = record.mRequest;
864 providerRequest.locationRequests.add(locationRequest);
865 if (locationRequest.getInterval() < providerRequest.interval) {
866 providerRequest.reportLocation = true;
867 providerRequest.interval = locationRequest.getInterval();
868 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700869 }
870 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700871
872 if (providerRequest.reportLocation) {
873 // calculate who to blame for power
874 // This is somewhat arbitrary. We pick a threshold interval
875 // that is slightly higher that the minimum interval, and
876 // spread the blame across all applications with a request
877 // under that threshold.
878 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
879 for (UpdateRecord record : records) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700880 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
881 LocationRequest locationRequest = record.mRequest;
882 if (locationRequest.getInterval() <= thresholdInterval) {
883 worksource.add(record.mReceiver.mUid);
884 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700885 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700886 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 }
888 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700889
890 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
891 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 }
893
894 private class UpdateRecord {
895 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700896 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400898 Location mLastFixBroadcast;
899 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900
901 /**
902 * Note: must be constructed with lock held.
903 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700904 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700906 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908
909 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
910 if (records == null) {
911 records = new ArrayList<UpdateRecord>();
912 mRecordsByProvider.put(provider, records);
913 }
914 if (!records.contains(this)) {
915 records.add(this);
916 }
917 }
918
919 /**
920 * Method to be called when a record will no longer be used. Calling this multiple times
921 * must have the same effect as calling it once.
922 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700923 void disposeLocked(boolean removeReceiver) {
924 // remove from mRecordsByProvider
925 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
926 if (globalRecords != null) {
927 globalRecords.remove(this);
928 }
929
930 if (!removeReceiver) return; // the caller will handle the rest
931
932 // remove from Receiver#mUpdateRecords
933 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
934 if (receiverRecords != null) {
935 receiverRecords.remove(this.mProvider);
936
937 // and also remove the Receiver if it has no more update records
938 if (removeReceiver && receiverRecords.size() == 0) {
939 removeUpdatesLocked(mReceiver);
940 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 }
943
944 @Override
945 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700946 StringBuilder s = new StringBuilder();
947 s.append("UpdateRecord[");
948 s.append(mProvider);
949 s.append(' ').append(mReceiver.mPackageName).append('(');
950 s.append(mReceiver.mUid).append(')');
951 s.append(' ').append(mRequest);
952 s.append(']');
953 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 }
956
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700957 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400958 IBinder binder = listener.asBinder();
959 Receiver receiver = mReceivers.get(binder);
960 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700961 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400962 mReceivers.put(binder, receiver);
963
964 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700965 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400966 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800967 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400968 return null;
969 }
970 }
971 return receiver;
972 }
973
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700974 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400975 Receiver receiver = mReceivers.get(intent);
976 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700977 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400978 mReceivers.put(intent, receiver);
979 }
980 return receiver;
981 }
982
Victoria Lease09016ab2012-09-16 12:33:15 -0700983 private boolean isProviderAllowedByCoarsePermission(String provider) {
984 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
985 return true;
986 }
987 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
988 return true;
989 }
990 if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
991 return true;
992 }
993 return false;
994 }
995
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700996 private String checkPermissionAndRequest(LocationRequest request) {
997 String perm = checkPermission();
998
999 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001000 if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
1001 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1002 }
1003 switch (request.getQuality()) {
1004 case LocationRequest.ACCURACY_FINE:
1005 request.setQuality(LocationRequest.ACCURACY_BLOCK);
1006 break;
1007 case LocationRequest.POWER_HIGH:
1008 request.setQuality(LocationRequest.POWER_LOW);
1009 break;
1010 }
1011 // throttle
1012 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1013 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1014 }
1015 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1016 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1017 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001018 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001019 // make getFastestInterval() the minimum of interval and fastest interval
1020 if (request.getFastestInterval() > request.getInterval()) {
1021 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001022 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001023 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001024 }
1025
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001026 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001027 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001028 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001029 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001030 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001031 String[] packages = mPackageManager.getPackagesForUid(uid);
1032 if (packages == null) {
1033 throw new SecurityException("invalid UID " + uid);
1034 }
1035 for (String pkg : packages) {
1036 if (packageName.equals(pkg)) return;
1037 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001038 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001039 }
1040
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001041 private void checkPendingIntent(PendingIntent intent) {
1042 if (intent == null) {
1043 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001044 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001045 }
1046
1047 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1048 int pid, int uid, String packageName) {
1049 if (intent == null && listener == null) {
1050 throw new IllegalArgumentException("need eiter listener or intent");
1051 } else if (intent != null && listener != null) {
1052 throw new IllegalArgumentException("cannot register both listener and intent");
1053 } else if (intent != null) {
1054 checkPendingIntent(intent);
1055 return getReceiver(intent, pid, uid, packageName);
1056 } else {
1057 return getReceiver(listener, pid, uid, packageName);
1058 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001059 }
1060
Nick Pellye0fd6932012-07-11 10:26:13 -07001061 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001062 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1063 PendingIntent intent, String packageName) {
1064 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1065 checkPackageName(packageName);
1066 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001068 final int pid = Binder.getCallingPid();
1069 final int uid = Binder.getCallingUid();
1070 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001072 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 long identity = Binder.clearCallingIdentity();
1074 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001075 synchronized (mLock) {
1076 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001077 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 } finally {
1079 Binder.restoreCallingIdentity(identity);
1080 }
1081 }
1082
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001083 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1084 int pid, int uid, String packageName) {
1085 // Figure out the provider. Either its explicitly request (legacy use cases), or
1086 // use the fused provider
1087 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1088 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001089 if (name == null) {
1090 throw new IllegalArgumentException("provider name must not be null");
1091 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001092 LocationProviderInterface provider = mProvidersByName.get(name);
1093 if (provider == null) {
1094 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1095 }
1096
1097 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1098 name + " " + request + " from " + packageName + "(" + uid + ")");
1099
1100 UpdateRecord record = new UpdateRecord(name, request, receiver);
1101 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1102 if (oldRecord != null) {
1103 oldRecord.disposeLocked(false);
1104 }
1105
Victoria Leaseb711d572012-10-02 13:14:11 -07001106 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001107 if (isProviderEnabled) {
1108 applyRequirementsLocked(name);
1109 } else {
1110 // Notify the listener that updates are currently disabled
1111 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 }
1113 }
1114
Nick Pellye0fd6932012-07-11 10:26:13 -07001115 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001116 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1117 String packageName) {
1118 checkPackageName(packageName);
1119 checkPermission();
1120 final int pid = Binder.getCallingPid();
1121 final int uid = Binder.getCallingUid();
1122 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1123
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001124 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001125 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001127 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001128 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001130 } finally {
1131 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 }
1133 }
1134
1135 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001136 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1137
1138 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1139 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1140 synchronized (receiver) {
1141 if (receiver.mPendingBroadcasts > 0) {
1142 decrementPendingBroadcasts();
1143 receiver.mPendingBroadcasts = 0;
1144 }
1145 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 }
1147
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001148 // Record which providers were associated with this listener
1149 HashSet<String> providers = new HashSet<String>();
1150 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1151 if (oldRecords != null) {
1152 // Call dispose() on the obsolete update records.
1153 for (UpdateRecord record : oldRecords.values()) {
1154 record.disposeLocked(false);
1155 }
1156 // Accumulate providers
1157 providers.addAll(oldRecords.keySet());
1158 }
1159
1160 // update provider
1161 for (String provider : providers) {
1162 // If provider is already disabled, don't need to do anything
Victoria Leaseb711d572012-10-02 13:14:11 -07001163 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001164 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 }
1166
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001167 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 }
1169 }
1170
Nick Pellye0fd6932012-07-11 10:26:13 -07001171 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001172 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001173 if (D) Log.d(TAG, "getLastLocation: " + request);
1174 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1175 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001176 checkPackageName(packageName);
1177
Victoria Leaseb711d572012-10-02 13:14:11 -07001178 long identity = Binder.clearCallingIdentity();
1179 try {
1180 if (mBlacklist.isBlacklisted(packageName)) {
1181 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1182 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001183 return null;
1184 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001185
1186 synchronized (mLock) {
1187 // Figure out the provider. Either its explicitly request (deprecated API's),
1188 // or use the fused provider
1189 String name = request.getProvider();
1190 if (name == null) name = LocationManager.FUSED_PROVIDER;
1191 LocationProviderInterface provider = mProvidersByName.get(name);
1192 if (provider == null) return null;
1193
1194 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
1195
1196 Location location = mLastLocation.get(name);
1197 if (location == null) {
1198 return null;
1199 }
1200 if (ACCESS_FINE_LOCATION.equals(perm)) {
1201 return location;
1202 } else {
1203 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1204 if (noGPSLocation != null) {
1205 return mLocationFudger.getOrCreate(noGPSLocation);
1206 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001207 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001208 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001209 return null;
1210 } finally {
1211 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001212 }
1213 }
1214
1215 @Override
1216 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1217 String packageName) {
1218 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001219 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001220 checkPermissionAndRequest(request);
1221 checkPendingIntent(intent);
1222 checkPackageName(packageName);
1223
1224 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1225
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001226 // geo-fence manager uses the public location API, need to clear identity
1227 int uid = Binder.getCallingUid();
1228 long identity = Binder.clearCallingIdentity();
1229 try {
1230 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1231 } finally {
1232 Binder.restoreCallingIdentity(identity);
1233 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001234 }
1235
1236 @Override
1237 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001238 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001239 checkPendingIntent(intent);
1240 checkPackageName(packageName);
1241
1242 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1243
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001244 // geo-fence manager uses the public location API, need to clear identity
1245 long identity = Binder.clearCallingIdentity();
1246 try {
1247 mGeofenceManager.removeFence(geofence, intent);
1248 } finally {
1249 Binder.restoreCallingIdentity(identity);
1250 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001251 }
1252
1253
1254 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001256 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 return false;
1258 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001259 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 PackageManager.PERMISSION_GRANTED) {
1261 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1262 }
1263
1264 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001265 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001267 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 return false;
1269 }
1270 return true;
1271 }
1272
Nick Pellye0fd6932012-07-11 10:26:13 -07001273 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001275 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001276 try {
1277 mGpsStatusProvider.removeGpsStatusListener(listener);
1278 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001279 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 }
1282 }
1283
Nick Pellye0fd6932012-07-11 10:26:13 -07001284 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001286 if (provider == null) {
1287 // throw NullPointerException to remain compatible with previous implementation
1288 throw new NullPointerException();
1289 }
1290
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001291 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001293 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 != PackageManager.PERMISSION_GRANTED)) {
1295 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1296 }
1297
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001298 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001299 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001300 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001301
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001302 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 }
1304 }
1305
Nick Pellye0fd6932012-07-11 10:26:13 -07001306 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001307 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001308 if (Binder.getCallingUid() != Process.myUid()) {
1309 throw new SecurityException(
1310 "calling sendNiResponse from outside of the system is not allowed");
1311 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001312 try {
1313 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001314 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001315 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001316 return false;
1317 }
1318 }
1319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001321 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001322 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 * accessed by the caller
1324 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001325 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001326 public ProviderProperties getProviderProperties(String provider) {
1327 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001329 LocationProviderInterface p;
1330 synchronized (mLock) {
1331 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 }
1333
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001334 if (p == null) return null;
1335 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 }
1337
Nick Pellye0fd6932012-07-11 10:26:13 -07001338 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 public boolean isProviderEnabled(String provider) {
Victoria Leasef429921e2012-10-04 08:01:19 -07001340 String perms = checkPermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001341 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
Victoria Leasef429921e2012-10-04 08:01:19 -07001342 if (ACCESS_COARSE_LOCATION.equals(perms) &&
1343 !isProviderAllowedByCoarsePermission(provider)) {
1344 throw new SecurityException("The \"" + provider +
1345 "\" provider requires ACCESS_FINE_LOCATION permission");
1346 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001347
Victoria Leaseb711d572012-10-02 13:14:11 -07001348 long identity = Binder.clearCallingIdentity();
1349 try {
1350 synchronized (mLock) {
1351 LocationProviderInterface p = mProvidersByName.get(provider);
1352 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001353
Victoria Leaseb711d572012-10-02 13:14:11 -07001354 return isAllowedBySettingsLocked(provider, mCurrentUserId);
1355 }
1356 } finally {
1357 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001358 }
1359 }
1360
1361 private void checkCallerIsProvider() {
1362 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1363 == PackageManager.PERMISSION_GRANTED) {
1364 return;
1365 }
1366
1367 // Previously we only used the INSTALL_LOCATION_PROVIDER
1368 // check. But that is system or signature
1369 // protection level which is not flexible enough for
1370 // providers installed oustide the system image. So
1371 // also allow providers with a UID matching the
1372 // currently bound package name
1373
1374 int uid = Binder.getCallingUid();
1375
1376 if (mGeocodeProvider != null) {
1377 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1378 }
1379 for (LocationProviderProxy proxy : mProxyProviders) {
1380 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1381 }
1382 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1383 "or UID of a currently bound location provider");
1384 }
1385
1386 private boolean doesPackageHaveUid(int uid, String packageName) {
1387 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 return false;
1389 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001390 try {
1391 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1392 if (appInfo.uid != uid) {
1393 return false;
1394 }
1395 } catch (NameNotFoundException e) {
1396 return false;
1397 }
1398 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 }
1400
Nick Pellye0fd6932012-07-11 10:26:13 -07001401 @Override
Mike Lockwooda4903f252010-02-17 06:42:23 -05001402 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001403 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001404
Nick Pelly2eeeec22012-07-18 13:13:37 -07001405 if (!location.isComplete()) {
1406 Log.w(TAG, "Dropping incomplete location: " + location);
1407 return;
1408 }
1409
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001410 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1411 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f252010-02-17 06:42:23 -05001412 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001413 mLocationHandler.sendMessageAtFrontOfQueue(m);
1414 }
1415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416
1417 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1418 // Always broadcast the first update
1419 if (lastLoc == null) {
1420 return true;
1421 }
1422
Nick Pellyf1be6862012-05-15 10:53:42 -07001423 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001424 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001425 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001426 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 return false;
1428 }
1429
1430 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001431 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 if (minDistance > 0.0) {
1433 if (loc.distanceTo(lastLoc) <= minDistance) {
1434 return false;
1435 }
1436 }
1437
1438 return true;
1439 }
1440
Mike Lockwooda4903f252010-02-17 06:42:23 -05001441 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001442 if (D) Log.d(TAG, "incoming location: " + location);
1443
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001444 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f252010-02-17 06:42:23 -05001445 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446
Laurent Tu60ec50a2012-10-04 17:00:10 -07001447 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001448 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001449 if (p == null) return;
1450
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001451 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001452 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1453 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001454 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001455 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001456 lastLocation = new Location(provider);
1457 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001458 } else {
1459 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1460 if (noGPSLocation == null && lastNoGPSLocation != null) {
1461 // New location has no no-GPS location: adopt last no-GPS location. This is set
1462 // directly into location because we do not want to notify COARSE clients.
1463 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1464 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001465 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001466 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467
Laurent Tu60ec50a2012-10-04 17:00:10 -07001468 // Skip if there are no UpdateRecords for this provider.
1469 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1470 if (records == null || records.size() == 0) return;
1471
Victoria Lease09016ab2012-09-16 12:33:15 -07001472 // Fetch coarse location
1473 Location coarseLocation = null;
1474 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1475 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1476 }
1477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 // Fetch latest status update time
1479 long newStatusUpdateTime = p.getStatusUpdateTime();
1480
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001481 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 Bundle extras = new Bundle();
1483 int status = p.getStatus(extras);
1484
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001486 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001489 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001491 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001492
Victoria Leaseb711d572012-10-02 13:14:11 -07001493 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1494 if (receiverUserId != mCurrentUserId) {
1495 if (D) {
1496 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
1497 " (current user: " + mCurrentUserId + ", app: " +
1498 receiver.mPackageName + ")");
1499 }
1500 continue;
1501 }
1502
Nick Pelly4035f5a2012-08-17 14:43:49 -07001503 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1504 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1505 receiver.mPackageName);
1506 continue;
1507 }
1508
Victoria Lease09016ab2012-09-16 12:33:15 -07001509 Location notifyLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001510 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001511 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001512 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001513 notifyLocation = coarseLocation; // use coarse location if available
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001514 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001515 if (notifyLocation != null) {
1516 Location lastLoc = r.mLastFixBroadcast;
1517 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1518 if (lastLoc == null) {
1519 lastLoc = new Location(notifyLocation);
1520 r.mLastFixBroadcast = lastLoc;
1521 } else {
1522 lastLoc.set(notifyLocation);
1523 }
1524 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1525 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1526 receiverDead = true;
1527 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 }
1529 }
1530
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001531 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001532 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001533 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001535 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001537 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001538 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001539 }
1540 }
1541
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001542 // track expired records
1543 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1544 if (deadUpdateRecords == null) {
1545 deadUpdateRecords = new ArrayList<UpdateRecord>();
1546 }
1547 deadUpdateRecords.add(r);
1548 }
1549 // track dead receivers
1550 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001551 if (deadReceivers == null) {
1552 deadReceivers = new ArrayList<Receiver>();
1553 }
1554 if (!deadReceivers.contains(receiver)) {
1555 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 }
1557 }
1558 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001559
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001560 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001562 for (Receiver receiver : deadReceivers) {
1563 removeUpdatesLocked(receiver);
1564 }
1565 }
1566 if (deadUpdateRecords != null) {
1567 for (UpdateRecord r : deadUpdateRecords) {
1568 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 }
1570 }
1571 }
1572
1573 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 @Override
1575 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001576 switch (msg.what) {
1577 case MSG_LOCATION_CHANGED:
1578 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1579 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 }
1581 }
1582 }
1583
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001584 private void handleLocationChanged(Location location, boolean passive) {
1585 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001586
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001587 if (!passive) {
1588 // notify passive provider of the new location
1589 mPassiveProvider.updateLocation(location);
1590 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001592 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001593 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001594 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001596 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598
Mike Lockwoode97ae402010-09-29 15:23:46 -04001599 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1600 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001601 public void onPackageDisappeared(String packageName, int reason) {
1602 // remove all receivers associated with this package name
1603 synchronized (mLock) {
1604 ArrayList<Receiver> deadReceivers = null;
1605
1606 for (Receiver receiver : mReceivers.values()) {
1607 if (receiver.mPackageName.equals(packageName)) {
1608 if (deadReceivers == null) {
1609 deadReceivers = new ArrayList<Receiver>();
1610 }
1611 deadReceivers.add(receiver);
1612 }
1613 }
1614
1615 // perform removal outside of mReceivers loop
1616 if (deadReceivers != null) {
1617 for (Receiver receiver : deadReceivers) {
1618 removeUpdatesLocked(receiver);
1619 }
1620 }
1621 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001622 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001623 };
1624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 // Wake locks
1626
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001627 private void incrementPendingBroadcasts() {
1628 synchronized (mWakeLock) {
1629 if (mPendingBroadcasts++ == 0) {
1630 try {
1631 mWakeLock.acquire();
1632 log("Acquired wakelock");
1633 } catch (Exception e) {
1634 // This is to catch a runtime exception thrown when we try to release an
1635 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001636 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001637 }
1638 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001639 }
1640 }
1641
1642 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001643 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001644 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001645 try {
1646 // Release wake lock
1647 if (mWakeLock.isHeld()) {
1648 mWakeLock.release();
1649 log("Released wakelock");
1650 } else {
1651 log("Can't release wakelock again!");
1652 }
1653 } catch (Exception e) {
1654 // This is to catch a runtime exception thrown when we try to release an
1655 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001656 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001657 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001658 }
1659 }
1660 }
1661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 // Geocoder
1663
Nick Pellye0fd6932012-07-11 10:26:13 -07001664 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001665 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001666 return mGeocodeProvider != null;
1667 }
1668
Nick Pellye0fd6932012-07-11 10:26:13 -07001669 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001671 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001672 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001673 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1674 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001676 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 }
1678
Mike Lockwooda55c3212009-04-15 11:10:11 -04001679
Nick Pellye0fd6932012-07-11 10:26:13 -07001680 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001682 double lowerLeftLatitude, double lowerLeftLongitude,
1683 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001684 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001685
1686 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001687 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1688 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1689 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001691 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 }
1693
1694 // Mock Providers
1695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 private void checkMockPermissionsSafe() {
1697 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1698 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1699 if (!allowMocks) {
1700 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1701 }
1702
1703 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1704 PackageManager.PERMISSION_GRANTED) {
1705 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001706 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 }
1708
Nick Pellye0fd6932012-07-11 10:26:13 -07001709 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001710 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 checkMockPermissionsSafe();
1712
Mike Lockwooda4903f252010-02-17 06:42:23 -05001713 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1714 throw new IllegalArgumentException("Cannot mock the passive location provider");
1715 }
1716
Mike Lockwood86328a92009-10-23 08:38:25 -04001717 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001718 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001719 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001720 // remove the real provider if we are replacing GPS or network provider
1721 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001722 || LocationManager.NETWORK_PROVIDER.equals(name)
1723 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001724 LocationProviderInterface p = mProvidersByName.get(name);
1725 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001726 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001727 }
1728 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001729 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1731 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001732 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001733 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001734 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 updateProvidersLocked();
1736 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001737 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 }
1739
Nick Pellye0fd6932012-07-11 10:26:13 -07001740 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 public void removeTestProvider(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 Lockwood86328a92009-10-23 08:38:25 -04001748 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001749 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001750 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001751
1752 // reinstate real provider if available
1753 LocationProviderInterface realProvider = mRealProviders.get(provider);
1754 if (realProvider != null) {
1755 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001756 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001757 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001759 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 }
1761 }
1762
Nick Pellye0fd6932012-07-11 10:26:13 -07001763 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 public void setTestProviderLocation(String provider, Location loc) {
1765 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001766 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001767 MockProvider mockProvider = mMockProviders.get(provider);
1768 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1770 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001771 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1772 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001773 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001774 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 }
1776 }
1777
Nick Pellye0fd6932012-07-11 10:26:13 -07001778 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 public void clearTestProviderLocation(String provider) {
1780 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001781 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001782 MockProvider mockProvider = mMockProviders.get(provider);
1783 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1785 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001786 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 }
1788 }
1789
Nick Pellye0fd6932012-07-11 10:26:13 -07001790 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 public void setTestProviderEnabled(String provider, boolean enabled) {
1792 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001793 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001794 MockProvider mockProvider = mMockProviders.get(provider);
1795 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1797 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001798 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001800 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 mEnabledProviders.add(provider);
1802 mDisabledProviders.remove(provider);
1803 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001804 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 mEnabledProviders.remove(provider);
1806 mDisabledProviders.add(provider);
1807 }
1808 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001809 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001810 }
1811 }
1812
Nick Pellye0fd6932012-07-11 10:26:13 -07001813 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 public void clearTestProviderEnabled(String provider) {
1815 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001816 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001817 MockProvider mockProvider = mMockProviders.get(provider);
1818 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1820 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001821 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 mEnabledProviders.remove(provider);
1823 mDisabledProviders.remove(provider);
1824 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001825 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 }
1827 }
1828
Nick Pellye0fd6932012-07-11 10:26:13 -07001829 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1831 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001832 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001833 MockProvider mockProvider = mMockProviders.get(provider);
1834 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1836 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001837 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 }
1839 }
1840
Nick Pellye0fd6932012-07-11 10:26:13 -07001841 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001842 public void clearTestProviderStatus(String provider) {
1843 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001844 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001845 MockProvider mockProvider = mMockProviders.get(provider);
1846 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001847 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1848 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001849 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 }
1851 }
1852
1853 private void log(String log) {
1854 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001855 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 }
1857 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001858
1859 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1861 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1862 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001863 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 + Binder.getCallingPid()
1865 + ", uid=" + Binder.getCallingUid());
1866 return;
1867 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001868
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001869 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001870 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001872 for (Receiver receiver : mReceivers.values()) {
1873 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001876 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1877 pw.println(" " + entry.getKey() + ":");
1878 for (UpdateRecord record : entry.getValue()) {
1879 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 }
1881 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001883 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1884 String provider = entry.getKey();
1885 Location location = entry.getValue();
1886 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001888
Nick Pellye0fd6932012-07-11 10:26:13 -07001889 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001890
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 if (mEnabledProviders.size() > 0) {
1892 pw.println(" Enabled Providers:");
1893 for (String i : mEnabledProviders) {
1894 pw.println(" " + i);
1895 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 }
1898 if (mDisabledProviders.size() > 0) {
1899 pw.println(" Disabled Providers:");
1900 for (String i : mDisabledProviders) {
1901 pw.println(" " + i);
1902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001903 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001904 pw.append(" ");
1905 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 if (mMockProviders.size() > 0) {
1907 pw.println(" Mock Providers:");
1908 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001909 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 }
1911 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001912
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001913 pw.append(" fudger: ");
1914 mLocationFudger.dump(fd, pw, args);
1915
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001916 if (args.length > 0 && "short".equals(args[0])) {
1917 return;
1918 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001919 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001920 pw.print(provider.getName() + " Internal State");
1921 if (provider instanceof LocationProviderProxy) {
1922 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1923 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001924 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001925 pw.println(":");
1926 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001927 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 }
1929 }
1930}