blob: c85541881253fc223fdd2add57a80b3cb3c3b9bf [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>();
Jeff Hamilton20de1602012-10-05 02:32:52 -0500278 String[] pkgs1 = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700279 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamilton20de1602012-10-05 02:32:52 -0500280 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));
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700286
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());
311 } else {
312 Slog.e(TAG, "no fused location provider found",
313 new IllegalStateException("Location service needs a fused location provider"));
314 }
315
316 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700317 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
318 mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700319 if (mGeocodeProvider == null) {
320 Slog.e(TAG, "no geocoder provider found");
321 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700322 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700325 * Called when the device's active user changes.
326 * @param userId the new active user's UserId
327 */
328 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700329 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700330 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700331 mLastLocation.clear();
332 for (LocationProviderInterface p : mProviders) {
333 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
334 p.switchUser(userId);
335 }
Victoria Lease38389b62012-09-30 11:44:22 -0700336 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700337 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700338 }
339 }
340
341 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
343 * location updates.
344 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700345 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700346 final int mUid; // uid of receiver
347 final int mPid; // pid of receiver
348 final String mPackageName; // package name of receiver
349 final String mPermission; // best permission that receiver has
350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 final ILocationListener mListener;
352 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700354
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400355 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700356
Mike Lockwood48f17512009-04-23 09:12:08 -0700357 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700359 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
360 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700363 if (listener != null) {
364 mKey = listener.asBinder();
365 } else {
366 mKey = intent;
367 }
368 mPermission = checkPermission();
369 mUid = uid;
370 mPid = pid;
371 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 }
373
374 @Override
375 public boolean equals(Object otherObj) {
376 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700377 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 }
379 return false;
380 }
381
382 @Override
383 public int hashCode() {
384 return mKey.hashCode();
385 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 @Override
388 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700389 StringBuilder s = new StringBuilder();
390 s.append("Reciever[");
391 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700393 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700395 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700397 for (String p : mUpdateRecords.keySet()) {
398 s.append(" ").append(mUpdateRecords.get(p).toString());
399 }
400 s.append("]");
401 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 }
403
404 public boolean isListener() {
405 return mListener != null;
406 }
407
408 public boolean isPendingIntent() {
409 return mPendingIntent != null;
410 }
411
412 public ILocationListener getListener() {
413 if (mListener != null) {
414 return mListener;
415 }
416 throw new IllegalStateException("Request for non-existent listener");
417 }
418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
420 if (mListener != null) {
421 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700422 synchronized (this) {
423 // synchronize to ensure incrementPendingBroadcastsLocked()
424 // is called before decrementPendingBroadcasts()
425 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700426 // call this after broadcasting so we do not increment
427 // if we throw an exeption.
428 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 } catch (RemoteException e) {
431 return false;
432 }
433 } else {
434 Intent statusChanged = new Intent();
435 statusChanged.putExtras(extras);
436 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
437 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700438 synchronized (this) {
439 // synchronize to ensure incrementPendingBroadcastsLocked()
440 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700441 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700442 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700443 // call this after broadcasting so we do not increment
444 // if we throw an exeption.
445 incrementPendingBroadcastsLocked();
446 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 } catch (PendingIntent.CanceledException e) {
448 return false;
449 }
450 }
451 return true;
452 }
453
454 public boolean callLocationChangedLocked(Location location) {
455 if (mListener != null) {
456 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700457 synchronized (this) {
458 // synchronize to ensure incrementPendingBroadcastsLocked()
459 // is called before decrementPendingBroadcasts()
460 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700461 // call this after broadcasting so we do not increment
462 // if we throw an exeption.
463 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 } catch (RemoteException e) {
466 return false;
467 }
468 } else {
469 Intent locationChanged = new Intent();
470 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
471 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700472 synchronized (this) {
473 // synchronize to ensure incrementPendingBroadcastsLocked()
474 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700475 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700476 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700477 // call this after broadcasting so we do not increment
478 // if we throw an exeption.
479 incrementPendingBroadcastsLocked();
480 }
481 } catch (PendingIntent.CanceledException e) {
482 return false;
483 }
484 }
485 return true;
486 }
487
488 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
489 if (mListener != null) {
490 try {
491 synchronized (this) {
492 // synchronize to ensure incrementPendingBroadcastsLocked()
493 // is called before decrementPendingBroadcasts()
494 if (enabled) {
495 mListener.onProviderEnabled(provider);
496 } else {
497 mListener.onProviderDisabled(provider);
498 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700499 // call this after broadcasting so we do not increment
500 // if we throw an exeption.
501 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700502 }
503 } catch (RemoteException e) {
504 return false;
505 }
506 } else {
507 Intent providerIntent = new Intent();
508 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
509 try {
510 synchronized (this) {
511 // synchronize to ensure incrementPendingBroadcastsLocked()
512 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700513 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700514 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700515 // call this after broadcasting so we do not increment
516 // if we throw an exeption.
517 incrementPendingBroadcastsLocked();
518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 } catch (PendingIntent.CanceledException e) {
520 return false;
521 }
522 }
523 return true;
524 }
525
Nick Pellyf1be6862012-05-15 10:53:42 -0700526 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700528 if (D) Log.d(TAG, "Location listener died");
529
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400530 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 removeUpdatesLocked(this);
532 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700533 synchronized (this) {
534 if (mPendingBroadcasts > 0) {
535 LocationManagerService.this.decrementPendingBroadcasts();
536 mPendingBroadcasts = 0;
537 }
538 }
539 }
540
Nick Pellye0fd6932012-07-11 10:26:13 -0700541 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700542 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
543 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400544 synchronized (this) {
545 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700546 }
547 }
548
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400549 // this must be called while synchronized by caller in a synchronized block
550 // containing the sending of the broadcaset
551 private void incrementPendingBroadcastsLocked() {
552 if (mPendingBroadcasts++ == 0) {
553 LocationManagerService.this.incrementPendingBroadcasts();
554 }
555 }
556
557 private void decrementPendingBroadcastsLocked() {
558 if (--mPendingBroadcasts == 0) {
559 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700560 }
561 }
562 }
563
Nick Pellye0fd6932012-07-11 10:26:13 -0700564 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700565 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400566 //Do not use getReceiver here as that will add the ILocationListener to
567 //the receiver list if it is not found. If it is not found then the
568 //LocationListener was removed when it had a pending broadcast and should
569 //not be added back.
570 IBinder binder = listener.asBinder();
571 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700572 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400573 synchronized (receiver) {
574 // so wakelock calls will succeed
575 long identity = Binder.clearCallingIdentity();
576 receiver.decrementPendingBroadcastsLocked();
577 Binder.restoreCallingIdentity(identity);
578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 }
580 }
581
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700582 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400583 mProviders.add(provider);
584 mProvidersByName.put(provider.getName(), provider);
585 }
586
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700587 private void removeProviderLocked(LocationProviderInterface provider) {
588 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400589 mProviders.remove(provider);
590 mProvidersByName.remove(provider.getName());
591 }
592
Mike Lockwood3d12b512009-04-21 23:25:35 -0700593
Victoria Leaseb711d572012-10-02 13:14:11 -0700594 private boolean isAllowedBySettingsLocked(String provider, int userId) {
595 if (userId != mCurrentUserId) {
596 return false;
597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 if (mEnabledProviders.contains(provider)) {
599 return true;
600 }
601 if (mDisabledProviders.contains(provider)) {
602 return false;
603 }
604 // Use system settings
605 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606
Victoria Leaseb711d572012-10-02 13:14:11 -0700607 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 }
609
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700610 /**
611 * Throw SecurityException if caller has neither COARSE or FINE.
612 * Otherwise, return the best permission.
613 */
614 private String checkPermission() {
615 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
616 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700617 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700618 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
619 PackageManager.PERMISSION_GRANTED) {
620 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700622
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700623 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
Victoria Lease4fab68b2012-09-13 13:20:59 -0700624 " ACCESS_FINE_LOCATION permission");
625 }
626
627 /**
628 * Throw SecurityException if caller lacks permission to use Geofences.
629 */
630 private void checkGeofencePermission() {
631 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
632 PackageManager.PERMISSION_GRANTED) {
633 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
634 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 }
636
Victoria Lease8dbb6342012-09-21 16:55:53 -0700637 private boolean isAllowedProviderSafe(String provider) {
638 if (LocationManager.GPS_PROVIDER.equals(provider) ||
639 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
640 // gps and passive providers require FINE permission
641 return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
642 == PackageManager.PERMISSION_GRANTED;
643 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
644 LocationManager.FUSED_PROVIDER.equals(provider)) {
645 // network and fused providers are ok with COARSE or FINE
646 return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
647 == PackageManager.PERMISSION_GRANTED) ||
648 (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
649 == PackageManager.PERMISSION_GRANTED);
Laurent Tu941221c2012-10-04 14:21:52 -0700650 } else {
651 // mock providers
652 LocationProviderInterface lp = mMockProviders.get(provider);
653 if (lp != null) {
654 ProviderProperties properties = lp.getProperties();
655 if (properties != null) {
656 if (properties.mRequiresSatellite) {
657 // provider requiring satellites require FINE permission
658 return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
659 == PackageManager.PERMISSION_GRANTED;
660 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
661 // provider requiring network and or cell require COARSE or FINE
662 return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
663 == PackageManager.PERMISSION_GRANTED) ||
664 (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
665 == PackageManager.PERMISSION_GRANTED);
666 }
667 }
668 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700669 }
Laurent Tu941221c2012-10-04 14:21:52 -0700670
Victoria Lease8dbb6342012-09-21 16:55:53 -0700671 return false;
672 }
673
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700674 /**
675 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700676 * fused, also including ones that are not permitted to
677 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700678 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700679 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700681 ArrayList<String> out;
682 synchronized (mLock) {
683 out = new ArrayList<String>(mProviders.size());
684 for (LocationProviderInterface provider : mProviders) {
685 String name = provider.getName();
686 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700687 continue;
688 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 out.add(name);
690 }
691 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700692
693 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 return out;
695 }
696
Mike Lockwood03ca2162010-04-01 08:10:09 -0700697 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700698 * Return all providers by name, that match criteria and are optionally
699 * enabled.
700 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700701 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700702 @Override
703 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700704 ArrayList<String> out;
Victoria Leaseb711d572012-10-02 13:14:11 -0700705 int callingUserId = UserHandle.getCallingUserId();
706 long identity = Binder.clearCallingIdentity();
707 try {
708 synchronized (mLock) {
709 out = new ArrayList<String>(mProviders.size());
710 for (LocationProviderInterface provider : mProviders) {
711 String name = provider.getName();
712 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700713 continue;
714 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700715 if (isAllowedProviderSafe(name)) {
716 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
717 continue;
718 }
719 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
720 name, provider.getProperties(), criteria)) {
721 continue;
722 }
723 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700724 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700725 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700726 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700727 } finally {
728 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700729 }
730
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700731 if (D) Log.d(TAG, "getProviders()=" + out);
732 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700733 }
734
735 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700736 * Return the name of the best provider given a Criteria object.
737 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700738 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700739 * has been deprecated as well. So this method now uses
740 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700741 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700742 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700743 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700744 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700745
746 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700747 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700748 result = pickBest(providers);
749 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
750 return result;
751 }
752 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700753 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700754 result = pickBest(providers);
755 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
756 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700757 }
758
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700759 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700760 return null;
761 }
762
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700763 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700764 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700765 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700766 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
767 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700768 } else {
769 return providers.get(0);
770 }
771 }
772
Nick Pellye0fd6932012-07-11 10:26:13 -0700773 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700774 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700775 checkPermission();
776
Mike Lockwood03ca2162010-04-01 08:10:09 -0700777 LocationProviderInterface p = mProvidersByName.get(provider);
778 if (p == null) {
779 throw new IllegalArgumentException("provider=" + provider);
780 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700781
782 boolean result = LocationProvider.propertiesMeetCriteria(
783 p.getName(), p.getProperties(), criteria);
784 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
785 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700786 }
787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700789 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400790 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500791 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 boolean isEnabled = p.isEnabled();
793 String name = p.getName();
Victoria Leaseb711d572012-10-02 13:14:11 -0700794 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700796 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700797 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700799 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700800 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700802 }
803 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700804 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
805 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 }
807 }
808
Victoria Leaseb711d572012-10-02 13:14:11 -0700809 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 int listeners = 0;
811
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500812 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700813 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814
815 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
818 if (records != null) {
819 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700820 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 UpdateRecord record = records.get(i);
Victoria Leaseb711d572012-10-02 13:14:11 -0700822 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
823 // Sends a notification message to the receiver
824 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
825 if (deadReceivers == null) {
826 deadReceivers = new ArrayList<Receiver>();
827 }
828 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700830 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 }
833 }
834
835 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700836 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 removeUpdatesLocked(deadReceivers.get(i));
838 }
839 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700840
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 if (enabled) {
842 p.enable();
843 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700844 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 }
846 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 }
850
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700851 private void applyRequirementsLocked(String provider) {
852 LocationProviderInterface p = mProvidersByName.get(provider);
853 if (p == null) return;
854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700856 WorkSource worksource = new WorkSource();
857 ProviderRequest providerRequest = new ProviderRequest();
858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700860 for (UpdateRecord record : records) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700861 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
862 LocationRequest locationRequest = record.mRequest;
863 providerRequest.locationRequests.add(locationRequest);
864 if (locationRequest.getInterval() < providerRequest.interval) {
865 providerRequest.reportLocation = true;
866 providerRequest.interval = locationRequest.getInterval();
867 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700868 }
869 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700870
871 if (providerRequest.reportLocation) {
872 // calculate who to blame for power
873 // This is somewhat arbitrary. We pick a threshold interval
874 // that is slightly higher that the minimum interval, and
875 // spread the blame across all applications with a request
876 // under that threshold.
877 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
878 for (UpdateRecord record : records) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700879 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
880 LocationRequest locationRequest = record.mRequest;
881 if (locationRequest.getInterval() <= thresholdInterval) {
882 worksource.add(record.mReceiver.mUid);
883 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700884 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700885 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 }
887 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700888
889 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
890 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 }
892
893 private class UpdateRecord {
894 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700895 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400897 Location mLastFixBroadcast;
898 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899
900 /**
901 * Note: must be constructed with lock held.
902 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700903 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700905 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907
908 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
909 if (records == null) {
910 records = new ArrayList<UpdateRecord>();
911 mRecordsByProvider.put(provider, records);
912 }
913 if (!records.contains(this)) {
914 records.add(this);
915 }
916 }
917
918 /**
919 * Method to be called when a record will no longer be used. Calling this multiple times
920 * must have the same effect as calling it once.
921 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700922 void disposeLocked(boolean removeReceiver) {
923 // remove from mRecordsByProvider
924 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
925 if (globalRecords != null) {
926 globalRecords.remove(this);
927 }
928
929 if (!removeReceiver) return; // the caller will handle the rest
930
931 // remove from Receiver#mUpdateRecords
932 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
933 if (receiverRecords != null) {
934 receiverRecords.remove(this.mProvider);
935
936 // and also remove the Receiver if it has no more update records
937 if (removeReceiver && receiverRecords.size() == 0) {
938 removeUpdatesLocked(mReceiver);
939 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400940 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 }
942
943 @Override
944 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700945 StringBuilder s = new StringBuilder();
946 s.append("UpdateRecord[");
947 s.append(mProvider);
948 s.append(' ').append(mReceiver.mPackageName).append('(');
949 s.append(mReceiver.mUid).append(')');
950 s.append(' ').append(mRequest);
951 s.append(']');
952 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 }
955
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700956 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400957 IBinder binder = listener.asBinder();
958 Receiver receiver = mReceivers.get(binder);
959 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700960 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400961 mReceivers.put(binder, receiver);
962
963 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700964 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400965 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800966 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400967 return null;
968 }
969 }
970 return receiver;
971 }
972
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700973 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400974 Receiver receiver = mReceivers.get(intent);
975 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700976 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400977 mReceivers.put(intent, receiver);
978 }
979 return receiver;
980 }
981
Victoria Lease09016ab2012-09-16 12:33:15 -0700982 private boolean isProviderAllowedByCoarsePermission(String provider) {
983 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
984 return true;
985 }
986 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
987 return true;
988 }
989 if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
990 return true;
991 }
992 return false;
993 }
994
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700995 private String checkPermissionAndRequest(LocationRequest request) {
996 String perm = checkPermission();
997
998 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Victoria Lease09016ab2012-09-16 12:33:15 -0700999 if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
1000 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1001 }
1002 switch (request.getQuality()) {
1003 case LocationRequest.ACCURACY_FINE:
1004 request.setQuality(LocationRequest.ACCURACY_BLOCK);
1005 break;
1006 case LocationRequest.POWER_HIGH:
1007 request.setQuality(LocationRequest.POWER_LOW);
1008 break;
1009 }
1010 // throttle
1011 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1012 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1013 }
1014 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1015 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1016 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001017 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001018 // make getFastestInterval() the minimum of interval and fastest interval
1019 if (request.getFastestInterval() > request.getInterval()) {
1020 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001021 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001022 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001023 }
1024
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001025 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001026 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001027 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001028 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001029 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001030 String[] packages = mPackageManager.getPackagesForUid(uid);
1031 if (packages == null) {
1032 throw new SecurityException("invalid UID " + uid);
1033 }
1034 for (String pkg : packages) {
1035 if (packageName.equals(pkg)) return;
1036 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001037 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001038 }
1039
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001040 private void checkPendingIntent(PendingIntent intent) {
1041 if (intent == null) {
1042 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001043 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001044 }
1045
1046 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1047 int pid, int uid, String packageName) {
1048 if (intent == null && listener == null) {
1049 throw new IllegalArgumentException("need eiter listener or intent");
1050 } else if (intent != null && listener != null) {
1051 throw new IllegalArgumentException("cannot register both listener and intent");
1052 } else if (intent != null) {
1053 checkPendingIntent(intent);
1054 return getReceiver(intent, pid, uid, packageName);
1055 } else {
1056 return getReceiver(listener, pid, uid, packageName);
1057 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001058 }
1059
Nick Pellye0fd6932012-07-11 10:26:13 -07001060 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001061 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1062 PendingIntent intent, String packageName) {
1063 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1064 checkPackageName(packageName);
1065 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001067 final int pid = Binder.getCallingPid();
1068 final int uid = Binder.getCallingUid();
1069 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001071 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 long identity = Binder.clearCallingIdentity();
1073 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001074 synchronized (mLock) {
1075 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 } finally {
1078 Binder.restoreCallingIdentity(identity);
1079 }
1080 }
1081
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001082 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1083 int pid, int uid, String packageName) {
1084 // Figure out the provider. Either its explicitly request (legacy use cases), or
1085 // use the fused provider
1086 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1087 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001088 if (name == null) {
1089 throw new IllegalArgumentException("provider name must not be null");
1090 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001091 LocationProviderInterface provider = mProvidersByName.get(name);
1092 if (provider == null) {
1093 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1094 }
1095
1096 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1097 name + " " + request + " from " + packageName + "(" + uid + ")");
1098
1099 UpdateRecord record = new UpdateRecord(name, request, receiver);
1100 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1101 if (oldRecord != null) {
1102 oldRecord.disposeLocked(false);
1103 }
1104
Victoria Leaseb711d572012-10-02 13:14:11 -07001105 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001106 if (isProviderEnabled) {
1107 applyRequirementsLocked(name);
1108 } else {
1109 // Notify the listener that updates are currently disabled
1110 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 }
1112 }
1113
Nick Pellye0fd6932012-07-11 10:26:13 -07001114 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001115 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1116 String packageName) {
1117 checkPackageName(packageName);
1118 checkPermission();
1119 final int pid = Binder.getCallingPid();
1120 final int uid = Binder.getCallingUid();
1121 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1122
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001123 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001124 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001126 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001127 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001129 } finally {
1130 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131 }
1132 }
1133
1134 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001135 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1136
1137 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1138 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1139 synchronized (receiver) {
1140 if (receiver.mPendingBroadcasts > 0) {
1141 decrementPendingBroadcasts();
1142 receiver.mPendingBroadcasts = 0;
1143 }
1144 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 }
1146
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001147 // Record which providers were associated with this listener
1148 HashSet<String> providers = new HashSet<String>();
1149 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1150 if (oldRecords != null) {
1151 // Call dispose() on the obsolete update records.
1152 for (UpdateRecord record : oldRecords.values()) {
1153 record.disposeLocked(false);
1154 }
1155 // Accumulate providers
1156 providers.addAll(oldRecords.keySet());
1157 }
1158
1159 // update provider
1160 for (String provider : providers) {
1161 // If provider is already disabled, don't need to do anything
Victoria Leaseb711d572012-10-02 13:14:11 -07001162 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001163 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 }
1165
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001166 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 }
1168 }
1169
Nick Pellye0fd6932012-07-11 10:26:13 -07001170 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001171 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001172 if (D) Log.d(TAG, "getLastLocation: " + request);
1173 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1174 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001175 checkPackageName(packageName);
1176
Victoria Leaseb711d572012-10-02 13:14:11 -07001177 long identity = Binder.clearCallingIdentity();
1178 try {
1179 if (mBlacklist.isBlacklisted(packageName)) {
1180 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1181 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001182 return null;
1183 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001184
1185 synchronized (mLock) {
1186 // Figure out the provider. Either its explicitly request (deprecated API's),
1187 // or use the fused provider
1188 String name = request.getProvider();
1189 if (name == null) name = LocationManager.FUSED_PROVIDER;
1190 LocationProviderInterface provider = mProvidersByName.get(name);
1191 if (provider == null) return null;
1192
1193 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
1194
1195 Location location = mLastLocation.get(name);
1196 if (location == null) {
1197 return null;
1198 }
1199 if (ACCESS_FINE_LOCATION.equals(perm)) {
1200 return location;
1201 } else {
1202 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1203 if (noGPSLocation != null) {
1204 return mLocationFudger.getOrCreate(noGPSLocation);
1205 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001206 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001207 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001208 return null;
1209 } finally {
1210 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001211 }
1212 }
1213
1214 @Override
1215 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1216 String packageName) {
1217 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001218 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001219 checkPermissionAndRequest(request);
1220 checkPendingIntent(intent);
1221 checkPackageName(packageName);
1222
1223 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1224
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001225 // geo-fence manager uses the public location API, need to clear identity
1226 int uid = Binder.getCallingUid();
1227 long identity = Binder.clearCallingIdentity();
1228 try {
1229 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1230 } finally {
1231 Binder.restoreCallingIdentity(identity);
1232 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001233 }
1234
1235 @Override
1236 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001237 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001238 checkPendingIntent(intent);
1239 checkPackageName(packageName);
1240
1241 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1242
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001243 // geo-fence manager uses the public location API, need to clear identity
1244 long identity = Binder.clearCallingIdentity();
1245 try {
1246 mGeofenceManager.removeFence(geofence, intent);
1247 } finally {
1248 Binder.restoreCallingIdentity(identity);
1249 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001250 }
1251
1252
1253 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001255 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 return false;
1257 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001258 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 PackageManager.PERMISSION_GRANTED) {
1260 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1261 }
1262
1263 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001264 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001266 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 return false;
1268 }
1269 return true;
1270 }
1271
Nick Pellye0fd6932012-07-11 10:26:13 -07001272 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001274 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001275 try {
1276 mGpsStatusProvider.removeGpsStatusListener(listener);
1277 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001278 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001279 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 }
1281 }
1282
Nick Pellye0fd6932012-07-11 10:26:13 -07001283 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001285 if (provider == null) {
1286 // throw NullPointerException to remain compatible with previous implementation
1287 throw new NullPointerException();
1288 }
1289
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001290 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001292 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 != PackageManager.PERMISSION_GRANTED)) {
1294 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1295 }
1296
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001297 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001298 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001299 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001300
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001301 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 }
1303 }
1304
Nick Pellye0fd6932012-07-11 10:26:13 -07001305 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001306 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001307 if (Binder.getCallingUid() != Process.myUid()) {
1308 throw new SecurityException(
1309 "calling sendNiResponse from outside of the system is not allowed");
1310 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001311 try {
1312 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001313 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001314 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001315 return false;
1316 }
1317 }
1318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001320 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001321 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 * accessed by the caller
1323 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001324 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001325 public ProviderProperties getProviderProperties(String provider) {
1326 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001328 LocationProviderInterface p;
1329 synchronized (mLock) {
1330 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 }
1332
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001333 if (p == null) return null;
1334 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 }
1336
Nick Pellye0fd6932012-07-11 10:26:13 -07001337 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001338 public boolean isProviderEnabled(String provider) {
Victoria Leasef429921e2012-10-04 08:01:19 -07001339 String perms = checkPermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001340 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
Victoria Leasef429921e2012-10-04 08:01:19 -07001341 if (ACCESS_COARSE_LOCATION.equals(perms) &&
1342 !isProviderAllowedByCoarsePermission(provider)) {
1343 throw new SecurityException("The \"" + provider +
1344 "\" provider requires ACCESS_FINE_LOCATION permission");
1345 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001346
Victoria Leaseb711d572012-10-02 13:14:11 -07001347 long identity = Binder.clearCallingIdentity();
1348 try {
1349 synchronized (mLock) {
1350 LocationProviderInterface p = mProvidersByName.get(provider);
1351 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001352
Victoria Leaseb711d572012-10-02 13:14:11 -07001353 return isAllowedBySettingsLocked(provider, mCurrentUserId);
1354 }
1355 } finally {
1356 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001357 }
1358 }
1359
1360 private void checkCallerIsProvider() {
1361 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1362 == PackageManager.PERMISSION_GRANTED) {
1363 return;
1364 }
1365
1366 // Previously we only used the INSTALL_LOCATION_PROVIDER
1367 // check. But that is system or signature
1368 // protection level which is not flexible enough for
1369 // providers installed oustide the system image. So
1370 // also allow providers with a UID matching the
1371 // currently bound package name
1372
1373 int uid = Binder.getCallingUid();
1374
1375 if (mGeocodeProvider != null) {
1376 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1377 }
1378 for (LocationProviderProxy proxy : mProxyProviders) {
1379 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1380 }
1381 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1382 "or UID of a currently bound location provider");
1383 }
1384
1385 private boolean doesPackageHaveUid(int uid, String packageName) {
1386 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 return false;
1388 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001389 try {
1390 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1391 if (appInfo.uid != uid) {
1392 return false;
1393 }
1394 } catch (NameNotFoundException e) {
1395 return false;
1396 }
1397 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 }
1399
Nick Pellye0fd6932012-07-11 10:26:13 -07001400 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001401 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001402 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001403
Nick Pelly2eeeec22012-07-18 13:13:37 -07001404 if (!location.isComplete()) {
1405 Log.w(TAG, "Dropping incomplete location: " + location);
1406 return;
1407 }
1408
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001409 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1410 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001411 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001412 mLocationHandler.sendMessageAtFrontOfQueue(m);
1413 }
1414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415
1416 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1417 // Always broadcast the first update
1418 if (lastLoc == null) {
1419 return true;
1420 }
1421
Nick Pellyf1be6862012-05-15 10:53:42 -07001422 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001423 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001424 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001425 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 return false;
1427 }
1428
1429 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001430 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 if (minDistance > 0.0) {
1432 if (loc.distanceTo(lastLoc) <= minDistance) {
1433 return false;
1434 }
1435 }
1436
1437 return true;
1438 }
1439
Mike Lockwooda4903f22010-02-17 06:42:23 -05001440 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001441 if (D) Log.d(TAG, "incoming location: " + location);
1442
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001443 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001444 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001446 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447
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
Victoria Lease09016ab2012-09-16 12:33:15 -07001468 // Fetch coarse location
1469 Location coarseLocation = null;
1470 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1471 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1472 }
1473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 // Fetch latest status update time
1475 long newStatusUpdateTime = p.getStatusUpdateTime();
1476
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001477 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 Bundle extras = new Bundle();
1479 int status = p.getStatus(extras);
1480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001482 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001483
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001484 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001485 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001487 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001488
Victoria Leaseb711d572012-10-02 13:14:11 -07001489 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1490 if (receiverUserId != mCurrentUserId) {
1491 if (D) {
1492 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
1493 " (current user: " + mCurrentUserId + ", app: " +
1494 receiver.mPackageName + ")");
1495 }
1496 continue;
1497 }
1498
Nick Pelly4035f5a2012-08-17 14:43:49 -07001499 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1500 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1501 receiver.mPackageName);
1502 continue;
1503 }
1504
Victoria Lease09016ab2012-09-16 12:33:15 -07001505 Location notifyLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001506 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001507 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001508 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001509 notifyLocation = coarseLocation; // use coarse location if available
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001510 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001511 if (notifyLocation != null) {
1512 Location lastLoc = r.mLastFixBroadcast;
1513 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1514 if (lastLoc == null) {
1515 lastLoc = new Location(notifyLocation);
1516 r.mLastFixBroadcast = lastLoc;
1517 } else {
1518 lastLoc.set(notifyLocation);
1519 }
1520 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1521 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1522 receiverDead = true;
1523 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 }
1525 }
1526
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001527 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001529 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001531 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001532 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001533 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001534 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001535 }
1536 }
1537
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001538 // track expired records
1539 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1540 if (deadUpdateRecords == null) {
1541 deadUpdateRecords = new ArrayList<UpdateRecord>();
1542 }
1543 deadUpdateRecords.add(r);
1544 }
1545 // track dead receivers
1546 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001547 if (deadReceivers == null) {
1548 deadReceivers = new ArrayList<Receiver>();
1549 }
1550 if (!deadReceivers.contains(receiver)) {
1551 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 }
1553 }
1554 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001555
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001556 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001558 for (Receiver receiver : deadReceivers) {
1559 removeUpdatesLocked(receiver);
1560 }
1561 }
1562 if (deadUpdateRecords != null) {
1563 for (UpdateRecord r : deadUpdateRecords) {
1564 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 }
1566 }
1567 }
1568
1569 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 @Override
1571 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001572 switch (msg.what) {
1573 case MSG_LOCATION_CHANGED:
1574 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1575 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 }
1577 }
1578 }
1579
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001580 private void handleLocationChanged(Location location, boolean passive) {
1581 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001582
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001583 if (!passive) {
1584 // notify passive provider of the new location
1585 mPassiveProvider.updateLocation(location);
1586 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001588 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001589 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001590 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001593 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594
Mike Lockwoode97ae402010-09-29 15:23:46 -04001595 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1596 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001597 public void onPackageDisappeared(String packageName, int reason) {
1598 // remove all receivers associated with this package name
1599 synchronized (mLock) {
1600 ArrayList<Receiver> deadReceivers = null;
1601
1602 for (Receiver receiver : mReceivers.values()) {
1603 if (receiver.mPackageName.equals(packageName)) {
1604 if (deadReceivers == null) {
1605 deadReceivers = new ArrayList<Receiver>();
1606 }
1607 deadReceivers.add(receiver);
1608 }
1609 }
1610
1611 // perform removal outside of mReceivers loop
1612 if (deadReceivers != null) {
1613 for (Receiver receiver : deadReceivers) {
1614 removeUpdatesLocked(receiver);
1615 }
1616 }
1617 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001618 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001619 };
1620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 // Wake locks
1622
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001623 private void incrementPendingBroadcasts() {
1624 synchronized (mWakeLock) {
1625 if (mPendingBroadcasts++ == 0) {
1626 try {
1627 mWakeLock.acquire();
1628 log("Acquired wakelock");
1629 } catch (Exception e) {
1630 // This is to catch a runtime exception thrown when we try to release an
1631 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001632 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001633 }
1634 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001635 }
1636 }
1637
1638 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001639 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001640 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001641 try {
1642 // Release wake lock
1643 if (mWakeLock.isHeld()) {
1644 mWakeLock.release();
1645 log("Released wakelock");
1646 } else {
1647 log("Can't release wakelock again!");
1648 }
1649 } catch (Exception e) {
1650 // This is to catch a runtime exception thrown when we try to release an
1651 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001652 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001653 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001654 }
1655 }
1656 }
1657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 // Geocoder
1659
Nick Pellye0fd6932012-07-11 10:26:13 -07001660 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001661 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001662 return mGeocodeProvider != null;
1663 }
1664
Nick Pellye0fd6932012-07-11 10:26:13 -07001665 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001667 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001668 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001669 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1670 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001672 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 }
1674
Mike Lockwooda55c3212009-04-15 11:10:11 -04001675
Nick Pellye0fd6932012-07-11 10:26:13 -07001676 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001678 double lowerLeftLatitude, double lowerLeftLongitude,
1679 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001680 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001681
1682 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001683 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1684 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1685 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001687 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 }
1689
1690 // Mock Providers
1691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 private void checkMockPermissionsSafe() {
1693 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1694 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1695 if (!allowMocks) {
1696 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1697 }
1698
1699 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1700 PackageManager.PERMISSION_GRANTED) {
1701 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001702 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 }
1704
Nick Pellye0fd6932012-07-11 10:26:13 -07001705 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001706 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 checkMockPermissionsSafe();
1708
Mike Lockwooda4903f22010-02-17 06:42:23 -05001709 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1710 throw new IllegalArgumentException("Cannot mock the passive location provider");
1711 }
1712
Mike Lockwood86328a92009-10-23 08:38:25 -04001713 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001714 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001715 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001716 // remove the real provider if we are replacing GPS or network provider
1717 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001718 || LocationManager.NETWORK_PROVIDER.equals(name)
1719 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001720 LocationProviderInterface p = mProvidersByName.get(name);
1721 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001722 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001723 }
1724 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001725 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1727 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001728 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001729 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001730 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 updateProvidersLocked();
1732 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001733 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 }
1735
Nick Pellye0fd6932012-07-11 10:26:13 -07001736 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 public void removeTestProvider(String provider) {
1738 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001739 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001740 MockProvider mockProvider = mMockProviders.get(provider);
1741 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1743 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001744 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001745 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001746 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001747
1748 // reinstate real provider if available
1749 LocationProviderInterface realProvider = mRealProviders.get(provider);
1750 if (realProvider != null) {
1751 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001752 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001753 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001755 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 }
1757 }
1758
Nick Pellye0fd6932012-07-11 10:26:13 -07001759 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 public void setTestProviderLocation(String provider, Location loc) {
1761 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001762 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001763 MockProvider mockProvider = mMockProviders.get(provider);
1764 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1766 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001767 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1768 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001769 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001770 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 }
1772 }
1773
Nick Pellye0fd6932012-07-11 10:26:13 -07001774 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 public void clearTestProviderLocation(String provider) {
1776 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001777 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001778 MockProvider mockProvider = mMockProviders.get(provider);
1779 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1781 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001782 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 }
1784 }
1785
Nick Pellye0fd6932012-07-11 10:26:13 -07001786 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 public void setTestProviderEnabled(String provider, boolean enabled) {
1788 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001789 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001790 MockProvider mockProvider = mMockProviders.get(provider);
1791 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1793 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001794 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001796 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 mEnabledProviders.add(provider);
1798 mDisabledProviders.remove(provider);
1799 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001800 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 mEnabledProviders.remove(provider);
1802 mDisabledProviders.add(provider);
1803 }
1804 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001805 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 }
1807 }
1808
Nick Pellye0fd6932012-07-11 10:26:13 -07001809 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001810 public void clearTestProviderEnabled(String provider) {
1811 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001812 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001813 MockProvider mockProvider = mMockProviders.get(provider);
1814 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1816 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001817 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 mEnabledProviders.remove(provider);
1819 mDisabledProviders.remove(provider);
1820 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001821 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 }
1823 }
1824
Nick Pellye0fd6932012-07-11 10:26:13 -07001825 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1827 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001828 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001829 MockProvider mockProvider = mMockProviders.get(provider);
1830 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001831 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1832 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001833 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 }
1835 }
1836
Nick Pellye0fd6932012-07-11 10:26:13 -07001837 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 public void clearTestProviderStatus(String provider) {
1839 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001840 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001841 MockProvider mockProvider = mMockProviders.get(provider);
1842 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1844 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001845 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001846 }
1847 }
1848
1849 private void log(String log) {
1850 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001851 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 }
1853 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001854
1855 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1857 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1858 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001859 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860 + Binder.getCallingPid()
1861 + ", uid=" + Binder.getCallingUid());
1862 return;
1863 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001864
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001865 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001867 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001868 for (Receiver receiver : mReceivers.values()) {
1869 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001870 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001872 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1873 pw.println(" " + entry.getKey() + ":");
1874 for (UpdateRecord record : entry.getValue()) {
1875 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 }
1877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001879 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1880 String provider = entry.getKey();
1881 Location location = entry.getValue();
1882 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001884
Nick Pellye0fd6932012-07-11 10:26:13 -07001885 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001886
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 if (mEnabledProviders.size() > 0) {
1888 pw.println(" Enabled Providers:");
1889 for (String i : mEnabledProviders) {
1890 pw.println(" " + i);
1891 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001892
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001893 }
1894 if (mDisabledProviders.size() > 0) {
1895 pw.println(" Disabled Providers:");
1896 for (String i : mDisabledProviders) {
1897 pw.println(" " + i);
1898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001900 pw.append(" ");
1901 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 if (mMockProviders.size() > 0) {
1903 pw.println(" Mock Providers:");
1904 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001905 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 }
1907 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001908
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001909 pw.append(" fudger: ");
1910 mLocationFudger.dump(fd, pw, args);
1911
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001912 if (args.length > 0 && "short".equals(args[0])) {
1913 return;
1914 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001915 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001916 pw.print(provider.getName() + " Internal State");
1917 if (provider instanceof LocationProviderProxy) {
1918 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1919 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001920 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001921 pw.println(":");
1922 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 }
1925 }
1926}