blob: 63eeeb32cecdbd24594c1fb9d1a8afeb06762ff9 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070020import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070024import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070027import android.content.pm.PackageManager.NameNotFoundException;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050028import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070029import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070031import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050032import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070033import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040035import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.location.ILocationListener;
37import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040038import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.Location;
40import android.location.LocationManager;
41import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070042import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.os.Binder;
44import android.os.Bundle;
45import android.os.Handler;
46import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070047import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.Message;
49import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070050import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070052import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070053import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070054import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080057import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
Mike Lockwoode97ae402010-09-29 15:23:46 -040059import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070060import com.android.internal.location.ProviderProperties;
61import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040062import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070063import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040064import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070065import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070066import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040067import com.android.server.location.LocationProviderInterface;
68import com.android.server.location.LocationProviderProxy;
69import com.android.server.location.MockProvider;
70import com.android.server.location.PassiveProvider;
71
72import java.io.FileDescriptor;
73import java.io.PrintWriter;
74import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070075import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040076import java.util.HashMap;
77import java.util.HashSet;
78import java.util.List;
79import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040080import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081
82/**
83 * The service class that manages LocationProviders and issues location
84 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 */
Brian Muramatsubb95cb92012-08-29 10:43:21 -070086public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070088 public static final boolean D = false;
89
90 private static final String WAKELOCK_KEY = TAG;
91 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 private static final String ACCESS_FINE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070094 android.Manifest.permission.ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 private static final String ACCESS_COARSE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070096 android.Manifest.permission.ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070098 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700100 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400101 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700102 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
103
104 private static final String NETWORK_LOCATION_SERVICE_ACTION =
105 "com.android.location.service.v2.NetworkLocationProvider";
106 private static final String FUSED_LOCATION_SERVICE_ACTION =
107 "com.android.location.service.FusedLocationProvider";
108
109 private static final int MSG_LOCATION_CHANGED = 1;
110
Nick Pellyf1be6862012-05-15 10:53:42 -0700111 // Location Providers may sometimes deliver location updates
112 // slightly faster that requested - provide grace period so
113 // we don't unnecessarily filter events that are otherwise on
114 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700115 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700116
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700117 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
118
119 private final Context mContext;
120
121 // used internally for synchronization
122 private final Object mLock = new Object();
123
124 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700125 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700126 private GeofenceManager mGeofenceManager;
127 private PowerManager.WakeLock mWakeLock;
128 private PackageManager mPackageManager;
129 private GeocoderProxy mGeocodeProvider;
130 private IGpsStatusProvider mGpsStatusProvider;
131 private INetInitiatedListener mNetInitiatedListener;
132 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700133 private PassiveProvider mPassiveProvider; // track passive provider for special cases
134 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700135
136 // --- fields below are protected by mWakeLock ---
137 private int mPendingBroadcasts;
138
139 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 // Set of providers that are explicitly enabled
141 private final Set<String> mEnabledProviders = new HashSet<String>();
142
143 // Set of providers that are explicitly disabled
144 private final Set<String> mDisabledProviders = new HashSet<String>();
145
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700146 // Mock (test) providers
147 private final HashMap<String, MockProvider> mMockProviders =
148 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700150 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400151 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700153 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500154 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400156
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700157 // real providers, saved here when mocked out
158 private final HashMap<String, LocationProviderInterface> mRealProviders =
159 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700161 // mapping from provider name to provider
162 private final HashMap<String, LocationProviderInterface> mProvidersByName =
163 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700165 // mapping from provider name to all its UpdateRecords
166 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
167 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // mapping from provider name to last known location
170 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172 // all providers that operate over proxy, for authorizing incoming location
173 private final ArrayList<LocationProviderProxy> mProxyProviders =
174 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175
Victoria Lease38389b62012-09-30 11:44:22 -0700176 // current active user on the device - other users are denied location data
177 private int mCurrentUserId = UserHandle.USER_OWNER;
178
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700179 public LocationManagerService(Context context) {
180 super();
181 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800182
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 if (D) Log.d(TAG, "Constructed");
184
185 // most startup is deferred until systemReady()
186 }
187
188 public void systemReady() {
189 Thread thread = new Thread(null, this, THREAD_NAME);
190 thread.start();
191 }
192
193 @Override
194 public void run() {
195 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
196 Looper.prepare();
197 mLocationHandler = new LocationWorkerHandler();
198 init();
199 Looper.loop();
200 }
201
202 private void init() {
203 if (D) Log.d(TAG, "init()");
204
205 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
206 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
207 mPackageManager = mContext.getPackageManager();
208
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700209 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
210 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700211 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700212
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700213 synchronized (mLock) {
214 loadProvidersLocked();
215 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700216
Nick Pelly4035f5a2012-08-17 14:43:49 -0700217 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700218
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700219 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700220 mContext.getContentResolver().registerContentObserver(
221 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
222 new ContentObserver(mLocationHandler) {
223 @Override
224 public void onChange(boolean selfChange) {
225 synchronized (mLock) {
226 updateProvidersLocked();
227 }
228 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700229 }, UserHandle.USER_ALL);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700230 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700231
Victoria Lease38389b62012-09-30 11:44:22 -0700232 // listen for user change
233 IntentFilter intentFilter = new IntentFilter();
234 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
235
236 mContext.registerReceiverAsUser(new BroadcastReceiver() {
237 @Override
238 public void onReceive(Context context, Intent intent) {
239 String action = intent.getAction();
240 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
241 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
242 }
243 }
244 }, UserHandle.ALL, intentFilter, null, null);
245
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700246 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700247 }
248
249 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700250 // create a passive location provider, which is always enabled
251 PassiveProvider passiveProvider = new PassiveProvider(this);
252 addProviderLocked(passiveProvider);
253 mEnabledProviders.add(passiveProvider.getName());
254 mPassiveProvider = passiveProvider;
255
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700256 if (GpsLocationProvider.isSupported()) {
257 // Create a gps location provider
258 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
259 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
260 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
261 addProviderLocked(gpsProvider);
262 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
263 }
264
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700265 /*
266 Load package name(s) containing location provider support.
267 These packages can contain services implementing location providers:
268 Geocoder Provider, Network Location Provider, and
269 Fused Location Provider. They will each be searched for
270 service components implementing these providers.
271 The location framework also has support for installation
272 of new location providers at run-time. The new package does not
273 have to be explicitly listed here, however it must have a signature
274 that matches the signature of at least one package on this list.
275 */
276 Resources resources = mContext.getResources();
277 ArrayList<String> providerPackageNames = new ArrayList<String>();
278 String[] pkgs1 = resources.getStringArray(
279 com.android.internal.R.array.config_locationProviderPackageNames);
280 String[] pkgs2 = resources.getStringArray(
281 com.android.internal.R.array.config_overlay_locationProviderPackageNames);
282 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
283 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
284 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
285 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
286
287 // bind to network provider
288 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
289 mContext,
290 LocationManager.NETWORK_PROVIDER,
291 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700292 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700293 if (networkProvider != null) {
294 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
295 mProxyProviders.add(networkProvider);
296 addProviderLocked(networkProvider);
297 } else {
298 Slog.w(TAG, "no network location provider found");
299 }
300
301 // bind to fused provider
302 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
303 mContext,
304 LocationManager.FUSED_PROVIDER,
305 FUSED_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700306 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700307 if (fusedLocationProvider != null) {
308 addProviderLocked(fusedLocationProvider);
309 mProxyProviders.add(fusedLocationProvider);
310 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700311 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700312 } else {
313 Slog.e(TAG, "no fused location provider found",
314 new IllegalStateException("Location service needs a fused location provider"));
315 }
316
317 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700318 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
319 mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700320 if (mGeocodeProvider == null) {
321 Slog.e(TAG, "no geocoder provider found");
322 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700323 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700326 * Called when the device's active user changes.
327 * @param userId the new active user's UserId
328 */
329 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700330 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700331 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700332 mLastLocation.clear();
333 for (LocationProviderInterface p : mProviders) {
334 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
335 p.switchUser(userId);
336 }
Victoria Lease38389b62012-09-30 11:44:22 -0700337 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700338 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700339 }
340 }
341
342 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
344 * location updates.
345 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700346 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700347 final int mUid; // uid of receiver
348 final int mPid; // pid of receiver
349 final String mPackageName; // package name of receiver
350 final String mPermission; // best permission that receiver has
351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 final ILocationListener mListener;
353 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700355
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400356 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700357
Mike Lockwood48f17512009-04-23 09:12:08 -0700358 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700360 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
361 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700364 if (listener != null) {
365 mKey = listener.asBinder();
366 } else {
367 mKey = intent;
368 }
369 mPermission = checkPermission();
370 mUid = uid;
371 mPid = pid;
372 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 }
374
375 @Override
376 public boolean equals(Object otherObj) {
377 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700378 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
380 return false;
381 }
382
383 @Override
384 public int hashCode() {
385 return mKey.hashCode();
386 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 @Override
389 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700390 StringBuilder s = new StringBuilder();
391 s.append("Reciever[");
392 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700394 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700396 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700398 for (String p : mUpdateRecords.keySet()) {
399 s.append(" ").append(mUpdateRecords.get(p).toString());
400 }
401 s.append("]");
402 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 }
404
405 public boolean isListener() {
406 return mListener != null;
407 }
408
409 public boolean isPendingIntent() {
410 return mPendingIntent != null;
411 }
412
413 public ILocationListener getListener() {
414 if (mListener != null) {
415 return mListener;
416 }
417 throw new IllegalStateException("Request for non-existent listener");
418 }
419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
421 if (mListener != null) {
422 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700423 synchronized (this) {
424 // synchronize to ensure incrementPendingBroadcastsLocked()
425 // is called before decrementPendingBroadcasts()
426 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700427 // call this after broadcasting so we do not increment
428 // if we throw an exeption.
429 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 } catch (RemoteException e) {
432 return false;
433 }
434 } else {
435 Intent statusChanged = new Intent();
436 statusChanged.putExtras(extras);
437 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
438 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700439 synchronized (this) {
440 // synchronize to ensure incrementPendingBroadcastsLocked()
441 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700442 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700443 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700444 // call this after broadcasting so we do not increment
445 // if we throw an exeption.
446 incrementPendingBroadcastsLocked();
447 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 } catch (PendingIntent.CanceledException e) {
449 return false;
450 }
451 }
452 return true;
453 }
454
455 public boolean callLocationChangedLocked(Location location) {
456 if (mListener != null) {
457 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700458 synchronized (this) {
459 // synchronize to ensure incrementPendingBroadcastsLocked()
460 // is called before decrementPendingBroadcasts()
461 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700462 // call this after broadcasting so we do not increment
463 // if we throw an exeption.
464 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700465 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 } catch (RemoteException e) {
467 return false;
468 }
469 } else {
470 Intent locationChanged = new Intent();
471 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
472 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700473 synchronized (this) {
474 // synchronize to ensure incrementPendingBroadcastsLocked()
475 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700476 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700477 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700478 // call this after broadcasting so we do not increment
479 // if we throw an exeption.
480 incrementPendingBroadcastsLocked();
481 }
482 } catch (PendingIntent.CanceledException e) {
483 return false;
484 }
485 }
486 return true;
487 }
488
489 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
490 if (mListener != null) {
491 try {
492 synchronized (this) {
493 // synchronize to ensure incrementPendingBroadcastsLocked()
494 // is called before decrementPendingBroadcasts()
495 if (enabled) {
496 mListener.onProviderEnabled(provider);
497 } else {
498 mListener.onProviderDisabled(provider);
499 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700500 // call this after broadcasting so we do not increment
501 // if we throw an exeption.
502 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700503 }
504 } catch (RemoteException e) {
505 return false;
506 }
507 } else {
508 Intent providerIntent = new Intent();
509 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
510 try {
511 synchronized (this) {
512 // synchronize to ensure incrementPendingBroadcastsLocked()
513 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700514 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700515 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700516 // call this after broadcasting so we do not increment
517 // if we throw an exeption.
518 incrementPendingBroadcastsLocked();
519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 } catch (PendingIntent.CanceledException e) {
521 return false;
522 }
523 }
524 return true;
525 }
526
Nick Pellyf1be6862012-05-15 10:53:42 -0700527 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700529 if (D) Log.d(TAG, "Location listener died");
530
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400531 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 removeUpdatesLocked(this);
533 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700534 synchronized (this) {
535 if (mPendingBroadcasts > 0) {
536 LocationManagerService.this.decrementPendingBroadcasts();
537 mPendingBroadcasts = 0;
538 }
539 }
540 }
541
Nick Pellye0fd6932012-07-11 10:26:13 -0700542 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700543 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
544 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400545 synchronized (this) {
546 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700547 }
548 }
549
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400550 // this must be called while synchronized by caller in a synchronized block
551 // containing the sending of the broadcaset
552 private void incrementPendingBroadcastsLocked() {
553 if (mPendingBroadcasts++ == 0) {
554 LocationManagerService.this.incrementPendingBroadcasts();
555 }
556 }
557
558 private void decrementPendingBroadcastsLocked() {
559 if (--mPendingBroadcasts == 0) {
560 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700561 }
562 }
563 }
564
Nick Pellye0fd6932012-07-11 10:26:13 -0700565 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700566 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400567 //Do not use getReceiver here as that will add the ILocationListener to
568 //the receiver list if it is not found. If it is not found then the
569 //LocationListener was removed when it had a pending broadcast and should
570 //not be added back.
571 IBinder binder = listener.asBinder();
572 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700573 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400574 synchronized (receiver) {
575 // so wakelock calls will succeed
576 long identity = Binder.clearCallingIdentity();
577 receiver.decrementPendingBroadcastsLocked();
578 Binder.restoreCallingIdentity(identity);
579 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 }
581 }
582
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700583 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400584 mProviders.add(provider);
585 mProvidersByName.put(provider.getName(), provider);
586 }
587
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700588 private void removeProviderLocked(LocationProviderInterface provider) {
589 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400590 mProviders.remove(provider);
591 mProvidersByName.remove(provider.getName());
592 }
593
Mike Lockwood3d12b512009-04-21 23:25:35 -0700594
Victoria Leaseb711d572012-10-02 13:14:11 -0700595 private boolean isAllowedBySettingsLocked(String provider, int userId) {
596 if (userId != mCurrentUserId) {
597 return false;
598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 if (mEnabledProviders.contains(provider)) {
600 return true;
601 }
602 if (mDisabledProviders.contains(provider)) {
603 return false;
604 }
605 // Use system settings
606 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607
Victoria Leaseb711d572012-10-02 13:14:11 -0700608 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 }
610
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700611 /**
Victoria Leaseda479c52012-10-15 15:24:16 -0700612 * Returns the best permission available to the caller.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700613 */
Victoria Leaseda479c52012-10-15 15:24:16 -0700614 private String getBestCallingPermission() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700615 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 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700622 return null;
623 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700624
Victoria Leaseda479c52012-10-15 15:24:16 -0700625 /**
626 * Throw SecurityException if caller has neither COARSE or FINE.
627 * Otherwise, return the best permission.
628 */
629 private String checkPermission() {
630 String perm = getBestCallingPermission();
631 if (perm == null) {
632 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
633 " ACCESS_FINE_LOCATION permission");
634 }
635 return perm;
Victoria Lease4fab68b2012-09-13 13:20:59 -0700636 }
637
638 /**
639 * Throw SecurityException if caller lacks permission to use Geofences.
640 */
641 private void checkGeofencePermission() {
642 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
643 PackageManager.PERMISSION_GRANTED) {
644 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 }
647
Victoria Leaseda479c52012-10-15 15:24:16 -0700648 private String getMinimumPermissionForProvider(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700649 if (LocationManager.GPS_PROVIDER.equals(provider) ||
650 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
651 // gps and passive providers require FINE permission
Victoria Leaseda479c52012-10-15 15:24:16 -0700652 return ACCESS_FINE_LOCATION;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700653 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
654 LocationManager.FUSED_PROVIDER.equals(provider)) {
655 // network and fused providers are ok with COARSE or FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700656 return ACCESS_COARSE_LOCATION;
Laurent Tu941221c2012-10-04 14:21:52 -0700657 } else {
658 // mock providers
659 LocationProviderInterface lp = mMockProviders.get(provider);
660 if (lp != null) {
661 ProviderProperties properties = lp.getProperties();
662 if (properties != null) {
663 if (properties.mRequiresSatellite) {
664 // provider requiring satellites require FINE permission
Victoria Leaseda479c52012-10-15 15:24:16 -0700665 return ACCESS_FINE_LOCATION;
Laurent Tu941221c2012-10-04 14:21:52 -0700666 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
667 // provider requiring network and or cell require COARSE or FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700668 return ACCESS_COARSE_LOCATION;
Laurent Tu941221c2012-10-04 14:21:52 -0700669 }
670 }
671 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700672 }
Laurent Tu941221c2012-10-04 14:21:52 -0700673
Victoria Leaseda479c52012-10-15 15:24:16 -0700674 return null;
675 }
676
677 private boolean isPermissionSufficient(String perm, String minPerm) {
678 if (ACCESS_FINE_LOCATION.equals(minPerm)) {
679 return ACCESS_FINE_LOCATION.equals(perm);
680 } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) {
681 return ACCESS_FINE_LOCATION.equals(perm) ||
682 ACCESS_COARSE_LOCATION.equals(perm);
683 } else {
684 return false;
685 }
686 }
687
688 private void checkPermissionForProvider(String perm, String provider) {
689 String minPerm = getMinimumPermissionForProvider(provider);
690 if (!isPermissionSufficient(perm, minPerm)) {
691 if (ACCESS_FINE_LOCATION.equals(minPerm)) {
692 throw new SecurityException("Location provider \"" + provider +
693 "\" requires ACCESS_FINE_LOCATION permission.");
694 } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) {
695 throw new SecurityException("Location provider \"" + provider +
696 "\" requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
697 } else {
698 throw new SecurityException("Insufficient permission for location provider \"" +
699 provider + "\".");
700 }
701 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700702 }
703
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700704 /**
705 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700706 * fused, also including ones that are not permitted to
707 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700708 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700709 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700711 ArrayList<String> out;
712 synchronized (mLock) {
713 out = new ArrayList<String>(mProviders.size());
714 for (LocationProviderInterface provider : mProviders) {
715 String name = provider.getName();
716 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700717 continue;
718 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 out.add(name);
720 }
721 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700722
723 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 return out;
725 }
726
Mike Lockwood03ca2162010-04-01 08:10:09 -0700727 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700728 * Return all providers by name, that match criteria and are optionally
729 * enabled.
730 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700731 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700732 @Override
733 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700734 ArrayList<String> out;
Victoria Leaseda479c52012-10-15 15:24:16 -0700735 String perm = getBestCallingPermission();
Victoria Leaseb711d572012-10-02 13:14:11 -0700736 int callingUserId = UserHandle.getCallingUserId();
737 long identity = Binder.clearCallingIdentity();
738 try {
739 synchronized (mLock) {
740 out = new ArrayList<String>(mProviders.size());
741 for (LocationProviderInterface provider : mProviders) {
742 String name = provider.getName();
743 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700744 continue;
745 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700746 if (isPermissionSufficient(perm, getMinimumPermissionForProvider(name))) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700747 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
748 continue;
749 }
750 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
751 name, provider.getProperties(), criteria)) {
752 continue;
753 }
754 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700755 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700756 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700757 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700758 } finally {
759 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700760 }
761
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700762 if (D) Log.d(TAG, "getProviders()=" + out);
763 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700764 }
765
766 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700767 * Return the name of the best provider given a Criteria object.
768 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700769 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700770 * has been deprecated as well. So this method now uses
771 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700772 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700773 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700774 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700775 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700776
777 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700778 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700779 result = pickBest(providers);
780 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
781 return result;
782 }
783 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700784 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700785 result = pickBest(providers);
786 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
787 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700788 }
789
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700790 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700791 return null;
792 }
793
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700794 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700795 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700796 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700797 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
798 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700799 } else {
800 return providers.get(0);
801 }
802 }
803
Nick Pellye0fd6932012-07-11 10:26:13 -0700804 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700805 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700806 checkPermission();
807
Mike Lockwood03ca2162010-04-01 08:10:09 -0700808 LocationProviderInterface p = mProvidersByName.get(provider);
809 if (p == null) {
810 throw new IllegalArgumentException("provider=" + provider);
811 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700812
813 boolean result = LocationProvider.propertiesMeetCriteria(
814 p.getName(), p.getProperties(), criteria);
815 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
816 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700817 }
818
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700820 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400821 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500822 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 boolean isEnabled = p.isEnabled();
824 String name = p.getName();
Victoria Leaseb711d572012-10-02 13:14:11 -0700825 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700827 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700828 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700830 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700831 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700833 }
834 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700835 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
836 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 }
838 }
839
Victoria Leaseb711d572012-10-02 13:14:11 -0700840 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 int listeners = 0;
842
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500843 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700844 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845
846 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
849 if (records != null) {
850 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700851 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 UpdateRecord record = records.get(i);
Victoria Leaseb711d572012-10-02 13:14:11 -0700853 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
854 // Sends a notification message to the receiver
855 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
856 if (deadReceivers == null) {
857 deadReceivers = new ArrayList<Receiver>();
858 }
859 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700861 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 }
864 }
865
866 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700867 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 removeUpdatesLocked(deadReceivers.get(i));
869 }
870 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 if (enabled) {
873 p.enable();
874 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700875 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 }
877 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 }
881
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700882 private void applyRequirementsLocked(String provider) {
883 LocationProviderInterface p = mProvidersByName.get(provider);
884 if (p == null) return;
885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700887 WorkSource worksource = new WorkSource();
888 ProviderRequest providerRequest = new ProviderRequest();
889
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700891 for (UpdateRecord record : records) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700892 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
893 LocationRequest locationRequest = record.mRequest;
894 providerRequest.locationRequests.add(locationRequest);
895 if (locationRequest.getInterval() < providerRequest.interval) {
896 providerRequest.reportLocation = true;
897 providerRequest.interval = locationRequest.getInterval();
898 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700899 }
900 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700901
902 if (providerRequest.reportLocation) {
903 // calculate who to blame for power
904 // This is somewhat arbitrary. We pick a threshold interval
905 // that is slightly higher that the minimum interval, and
906 // spread the blame across all applications with a request
907 // under that threshold.
908 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
909 for (UpdateRecord record : records) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700910 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
911 LocationRequest locationRequest = record.mRequest;
912 if (locationRequest.getInterval() <= thresholdInterval) {
913 worksource.add(record.mReceiver.mUid);
914 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700915 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 }
918 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700919
920 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
921 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 }
923
924 private class UpdateRecord {
925 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700926 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400928 Location mLastFixBroadcast;
929 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930
931 /**
932 * Note: must be constructed with lock held.
933 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700934 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700936 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938
939 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
940 if (records == null) {
941 records = new ArrayList<UpdateRecord>();
942 mRecordsByProvider.put(provider, records);
943 }
944 if (!records.contains(this)) {
945 records.add(this);
946 }
947 }
948
949 /**
950 * Method to be called when a record will no longer be used. Calling this multiple times
951 * must have the same effect as calling it once.
952 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700953 void disposeLocked(boolean removeReceiver) {
954 // remove from mRecordsByProvider
955 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
956 if (globalRecords != null) {
957 globalRecords.remove(this);
958 }
959
960 if (!removeReceiver) return; // the caller will handle the rest
961
962 // remove from Receiver#mUpdateRecords
963 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
964 if (receiverRecords != null) {
965 receiverRecords.remove(this.mProvider);
966
967 // and also remove the Receiver if it has no more update records
968 if (removeReceiver && receiverRecords.size() == 0) {
969 removeUpdatesLocked(mReceiver);
970 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400971 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
973
974 @Override
975 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700976 StringBuilder s = new StringBuilder();
977 s.append("UpdateRecord[");
978 s.append(mProvider);
979 s.append(' ').append(mReceiver.mPackageName).append('(');
980 s.append(mReceiver.mUid).append(')');
981 s.append(' ').append(mRequest);
982 s.append(']');
983 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 }
986
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700987 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400988 IBinder binder = listener.asBinder();
989 Receiver receiver = mReceivers.get(binder);
990 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700991 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400992 mReceivers.put(binder, receiver);
993
994 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700995 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400996 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800997 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400998 return null;
999 }
1000 }
1001 return receiver;
1002 }
1003
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001004 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001005 Receiver receiver = mReceivers.get(intent);
1006 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001007 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001008 mReceivers.put(intent, receiver);
1009 }
1010 return receiver;
1011 }
1012
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001013 private String checkPermissionAndRequest(LocationRequest request) {
Victoria Leaseda479c52012-10-15 15:24:16 -07001014 String perm = getBestCallingPermission();
1015 String provider = request.getProvider();
1016 checkPermissionForProvider(perm, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001017
1018 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001019 switch (request.getQuality()) {
1020 case LocationRequest.ACCURACY_FINE:
1021 request.setQuality(LocationRequest.ACCURACY_BLOCK);
1022 break;
1023 case LocationRequest.POWER_HIGH:
1024 request.setQuality(LocationRequest.POWER_LOW);
1025 break;
1026 }
1027 // throttle
1028 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1029 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
1030 }
1031 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1032 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
1033 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001034 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001035 // make getFastestInterval() the minimum of interval and fastest interval
1036 if (request.getFastestInterval() > request.getInterval()) {
1037 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001038 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001039 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001040 }
1041
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001042 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001043 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001044 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001045 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001046 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001047 String[] packages = mPackageManager.getPackagesForUid(uid);
1048 if (packages == null) {
1049 throw new SecurityException("invalid UID " + uid);
1050 }
1051 for (String pkg : packages) {
1052 if (packageName.equals(pkg)) return;
1053 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001054 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001055 }
1056
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001057 private void checkPendingIntent(PendingIntent intent) {
1058 if (intent == null) {
1059 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001060 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001061 }
1062
1063 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1064 int pid, int uid, String packageName) {
1065 if (intent == null && listener == null) {
1066 throw new IllegalArgumentException("need eiter listener or intent");
1067 } else if (intent != null && listener != null) {
1068 throw new IllegalArgumentException("cannot register both listener and intent");
1069 } else if (intent != null) {
1070 checkPendingIntent(intent);
1071 return getReceiver(intent, pid, uid, packageName);
1072 } else {
1073 return getReceiver(listener, pid, uid, packageName);
1074 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001075 }
1076
Nick Pellye0fd6932012-07-11 10:26:13 -07001077 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001078 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1079 PendingIntent intent, String packageName) {
1080 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1081 checkPackageName(packageName);
1082 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001084 final int pid = Binder.getCallingPid();
1085 final int uid = Binder.getCallingUid();
1086 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001088 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 long identity = Binder.clearCallingIdentity();
1090 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001091 synchronized (mLock) {
1092 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001093 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 } finally {
1095 Binder.restoreCallingIdentity(identity);
1096 }
1097 }
1098
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001099 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1100 int pid, int uid, String packageName) {
1101 // Figure out the provider. Either its explicitly request (legacy use cases), or
1102 // use the fused provider
1103 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1104 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001105 if (name == null) {
1106 throw new IllegalArgumentException("provider name must not be null");
1107 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001108 LocationProviderInterface provider = mProvidersByName.get(name);
1109 if (provider == null) {
1110 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1111 }
1112
1113 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1114 name + " " + request + " from " + packageName + "(" + uid + ")");
1115
1116 UpdateRecord record = new UpdateRecord(name, request, receiver);
1117 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1118 if (oldRecord != null) {
1119 oldRecord.disposeLocked(false);
1120 }
1121
Victoria Leaseb711d572012-10-02 13:14:11 -07001122 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001123 if (isProviderEnabled) {
1124 applyRequirementsLocked(name);
1125 } else {
1126 // Notify the listener that updates are currently disabled
1127 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 }
1129 }
1130
Nick Pellye0fd6932012-07-11 10:26:13 -07001131 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001132 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1133 String packageName) {
1134 checkPackageName(packageName);
1135 checkPermission();
1136 final int pid = Binder.getCallingPid();
1137 final int uid = Binder.getCallingUid();
1138 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1139
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001140 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001141 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001143 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001144 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001146 } finally {
1147 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 }
1149 }
1150
1151 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001152 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1153
1154 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1155 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1156 synchronized (receiver) {
1157 if (receiver.mPendingBroadcasts > 0) {
1158 decrementPendingBroadcasts();
1159 receiver.mPendingBroadcasts = 0;
1160 }
1161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
1163
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001164 // Record which providers were associated with this listener
1165 HashSet<String> providers = new HashSet<String>();
1166 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1167 if (oldRecords != null) {
1168 // Call dispose() on the obsolete update records.
1169 for (UpdateRecord record : oldRecords.values()) {
1170 record.disposeLocked(false);
1171 }
1172 // Accumulate providers
1173 providers.addAll(oldRecords.keySet());
1174 }
1175
1176 // update provider
1177 for (String provider : providers) {
1178 // If provider is already disabled, don't need to do anything
Victoria Leaseb711d572012-10-02 13:14:11 -07001179 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001180 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 }
1182
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001183 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 }
1185 }
1186
Nick Pellye0fd6932012-07-11 10:26:13 -07001187 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001188 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001189 if (D) Log.d(TAG, "getLastLocation: " + request);
1190 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1191 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001192 checkPackageName(packageName);
1193
Victoria Leaseb711d572012-10-02 13:14:11 -07001194 long identity = Binder.clearCallingIdentity();
1195 try {
1196 if (mBlacklist.isBlacklisted(packageName)) {
1197 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1198 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001199 return null;
1200 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001201
1202 synchronized (mLock) {
1203 // Figure out the provider. Either its explicitly request (deprecated API's),
1204 // or use the fused provider
1205 String name = request.getProvider();
1206 if (name == null) name = LocationManager.FUSED_PROVIDER;
1207 LocationProviderInterface provider = mProvidersByName.get(name);
1208 if (provider == null) return null;
1209
1210 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
1211
1212 Location location = mLastLocation.get(name);
1213 if (location == null) {
1214 return null;
1215 }
1216 if (ACCESS_FINE_LOCATION.equals(perm)) {
1217 return location;
1218 } else {
1219 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1220 if (noGPSLocation != null) {
1221 return mLocationFudger.getOrCreate(noGPSLocation);
1222 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001223 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001224 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001225 return null;
1226 } finally {
1227 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001228 }
1229 }
1230
1231 @Override
1232 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1233 String packageName) {
1234 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001235 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236 checkPermissionAndRequest(request);
1237 checkPendingIntent(intent);
1238 checkPackageName(packageName);
1239
1240 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1241
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001242 // geo-fence manager uses the public location API, need to clear identity
1243 int uid = Binder.getCallingUid();
1244 long identity = Binder.clearCallingIdentity();
1245 try {
1246 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1247 } finally {
1248 Binder.restoreCallingIdentity(identity);
1249 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001250 }
1251
1252 @Override
1253 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001254 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001255 checkPendingIntent(intent);
1256 checkPackageName(packageName);
1257
1258 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1259
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001260 // geo-fence manager uses the public location API, need to clear identity
1261 long identity = Binder.clearCallingIdentity();
1262 try {
1263 mGeofenceManager.removeFence(geofence, intent);
1264 } finally {
1265 Binder.restoreCallingIdentity(identity);
1266 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001267 }
1268
1269
1270 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001272 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 return false;
1274 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001275 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 PackageManager.PERMISSION_GRANTED) {
1277 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1278 }
1279
1280 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001281 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001283 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 return false;
1285 }
1286 return true;
1287 }
1288
Nick Pellye0fd6932012-07-11 10:26:13 -07001289 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001291 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001292 try {
1293 mGpsStatusProvider.removeGpsStatusListener(listener);
1294 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001295 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001296 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001297 }
1298 }
1299
Nick Pellye0fd6932012-07-11 10:26:13 -07001300 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001302 if (provider == null) {
1303 // throw NullPointerException to remain compatible with previous implementation
1304 throw new NullPointerException();
1305 }
1306
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001307 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001309 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 != PackageManager.PERMISSION_GRANTED)) {
1311 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1312 }
1313
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001314 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001315 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001316 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001317
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001318 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 }
1320 }
1321
Nick Pellye0fd6932012-07-11 10:26:13 -07001322 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001323 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001324 if (Binder.getCallingUid() != Process.myUid()) {
1325 throw new SecurityException(
1326 "calling sendNiResponse from outside of the system is not allowed");
1327 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001328 try {
1329 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001330 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001331 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001332 return false;
1333 }
1334 }
1335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001337 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001338 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 * accessed by the caller
1340 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001341 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001342 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001343 if (mProvidersByName.get(provider) == null) {
1344 return null;
1345 }
1346
Victoria Leaseda479c52012-10-15 15:24:16 -07001347 checkPermissionForProvider(getBestCallingPermission(), provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001349 LocationProviderInterface p;
1350 synchronized (mLock) {
1351 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 }
1353
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001354 if (p == null) return null;
1355 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 }
1357
Nick Pellye0fd6932012-07-11 10:26:13 -07001358 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 public boolean isProviderEnabled(String provider) {
Victoria Leaseda479c52012-10-15 15:24:16 -07001360 checkPermissionForProvider(getBestCallingPermission(), provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001361 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1362
Victoria Leaseb711d572012-10-02 13:14:11 -07001363 long identity = Binder.clearCallingIdentity();
1364 try {
1365 synchronized (mLock) {
1366 LocationProviderInterface p = mProvidersByName.get(provider);
1367 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001368
Victoria Leaseb711d572012-10-02 13:14:11 -07001369 return isAllowedBySettingsLocked(provider, mCurrentUserId);
1370 }
1371 } finally {
1372 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001373 }
1374 }
1375
1376 private void checkCallerIsProvider() {
1377 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1378 == PackageManager.PERMISSION_GRANTED) {
1379 return;
1380 }
1381
1382 // Previously we only used the INSTALL_LOCATION_PROVIDER
1383 // check. But that is system or signature
1384 // protection level which is not flexible enough for
1385 // providers installed oustide the system image. So
1386 // also allow providers with a UID matching the
1387 // currently bound package name
1388
1389 int uid = Binder.getCallingUid();
1390
1391 if (mGeocodeProvider != null) {
1392 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1393 }
1394 for (LocationProviderProxy proxy : mProxyProviders) {
1395 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1396 }
1397 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1398 "or UID of a currently bound location provider");
1399 }
1400
1401 private boolean doesPackageHaveUid(int uid, String packageName) {
1402 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 return false;
1404 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001405 try {
1406 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1407 if (appInfo.uid != uid) {
1408 return false;
1409 }
1410 } catch (NameNotFoundException e) {
1411 return false;
1412 }
1413 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 }
1415
Nick Pellye0fd6932012-07-11 10:26:13 -07001416 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001417 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001418 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001419
Nick Pelly2eeeec22012-07-18 13:13:37 -07001420 if (!location.isComplete()) {
1421 Log.w(TAG, "Dropping incomplete location: " + location);
1422 return;
1423 }
1424
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001425 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1426 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001427 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001428 mLocationHandler.sendMessageAtFrontOfQueue(m);
1429 }
1430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431
1432 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1433 // Always broadcast the first update
1434 if (lastLoc == null) {
1435 return true;
1436 }
1437
Nick Pellyf1be6862012-05-15 10:53:42 -07001438 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001439 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001440 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001441 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 return false;
1443 }
1444
1445 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001446 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447 if (minDistance > 0.0) {
1448 if (loc.distanceTo(lastLoc) <= minDistance) {
1449 return false;
1450 }
1451 }
1452
1453 return true;
1454 }
1455
Mike Lockwooda4903f22010-02-17 06:42:23 -05001456 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001457 if (D) Log.d(TAG, "incoming location: " + location);
1458
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001459 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001460 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461
Laurent Tu60ec50a2012-10-04 17:00:10 -07001462 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001463 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001464 if (p == null) return;
1465
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001466 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001467 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1468 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001469 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001470 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001471 lastLocation = new Location(provider);
1472 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001473 } else {
1474 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1475 if (noGPSLocation == null && lastNoGPSLocation != null) {
1476 // New location has no no-GPS location: adopt last no-GPS location. This is set
1477 // directly into location because we do not want to notify COARSE clients.
1478 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1479 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001480 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001481 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482
Laurent Tu60ec50a2012-10-04 17:00:10 -07001483 // Skip if there are no UpdateRecords for this provider.
1484 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1485 if (records == null || records.size() == 0) return;
1486
Victoria Lease09016ab2012-09-16 12:33:15 -07001487 // Fetch coarse location
1488 Location coarseLocation = null;
1489 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1490 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1491 }
1492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 // Fetch latest status update time
1494 long newStatusUpdateTime = p.getStatusUpdateTime();
1495
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001496 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 Bundle extras = new Bundle();
1498 int status = p.getStatus(extras);
1499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001501 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001504 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001506 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001507
Victoria Leaseb711d572012-10-02 13:14:11 -07001508 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1509 if (receiverUserId != mCurrentUserId) {
1510 if (D) {
1511 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
1512 " (current user: " + mCurrentUserId + ", app: " +
1513 receiver.mPackageName + ")");
1514 }
1515 continue;
1516 }
1517
Nick Pelly4035f5a2012-08-17 14:43:49 -07001518 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1519 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1520 receiver.mPackageName);
1521 continue;
1522 }
1523
Victoria Lease09016ab2012-09-16 12:33:15 -07001524 Location notifyLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001525 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001526 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001527 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001528 notifyLocation = coarseLocation; // use coarse location if available
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001529 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001530 if (notifyLocation != null) {
1531 Location lastLoc = r.mLastFixBroadcast;
1532 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1533 if (lastLoc == null) {
1534 lastLoc = new Location(notifyLocation);
1535 r.mLastFixBroadcast = lastLoc;
1536 } else {
1537 lastLoc.set(notifyLocation);
1538 }
1539 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1540 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1541 receiverDead = true;
1542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 }
1544 }
1545
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001546 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001548 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001550 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001552 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001553 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001554 }
1555 }
1556
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001557 // track expired records
1558 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1559 if (deadUpdateRecords == null) {
1560 deadUpdateRecords = new ArrayList<UpdateRecord>();
1561 }
1562 deadUpdateRecords.add(r);
1563 }
1564 // track dead receivers
1565 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001566 if (deadReceivers == null) {
1567 deadReceivers = new ArrayList<Receiver>();
1568 }
1569 if (!deadReceivers.contains(receiver)) {
1570 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 }
1572 }
1573 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001574
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001575 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001577 for (Receiver receiver : deadReceivers) {
1578 removeUpdatesLocked(receiver);
1579 }
1580 }
1581 if (deadUpdateRecords != null) {
1582 for (UpdateRecord r : deadUpdateRecords) {
1583 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 }
1585 }
1586 }
1587
1588 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001589 @Override
1590 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001591 switch (msg.what) {
1592 case MSG_LOCATION_CHANGED:
1593 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1594 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 }
1596 }
1597 }
1598
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001599 private void handleLocationChanged(Location location, boolean passive) {
1600 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001601
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001602 if (!passive) {
1603 // notify passive provider of the new location
1604 mPassiveProvider.updateLocation(location);
1605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001607 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001608 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001609 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613
Mike Lockwoode97ae402010-09-29 15:23:46 -04001614 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1615 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001616 public void onPackageDisappeared(String packageName, int reason) {
1617 // remove all receivers associated with this package name
1618 synchronized (mLock) {
1619 ArrayList<Receiver> deadReceivers = null;
1620
1621 for (Receiver receiver : mReceivers.values()) {
1622 if (receiver.mPackageName.equals(packageName)) {
1623 if (deadReceivers == null) {
1624 deadReceivers = new ArrayList<Receiver>();
1625 }
1626 deadReceivers.add(receiver);
1627 }
1628 }
1629
1630 // perform removal outside of mReceivers loop
1631 if (deadReceivers != null) {
1632 for (Receiver receiver : deadReceivers) {
1633 removeUpdatesLocked(receiver);
1634 }
1635 }
1636 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001637 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001638 };
1639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 // Wake locks
1641
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001642 private void incrementPendingBroadcasts() {
1643 synchronized (mWakeLock) {
1644 if (mPendingBroadcasts++ == 0) {
1645 try {
1646 mWakeLock.acquire();
1647 log("Acquired wakelock");
1648 } catch (Exception e) {
1649 // This is to catch a runtime exception thrown when we try to release an
1650 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001651 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001652 }
1653 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001654 }
1655 }
1656
1657 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001658 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001659 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001660 try {
1661 // Release wake lock
1662 if (mWakeLock.isHeld()) {
1663 mWakeLock.release();
1664 log("Released wakelock");
1665 } else {
1666 log("Can't release wakelock again!");
1667 }
1668 } catch (Exception e) {
1669 // This is to catch a runtime exception thrown when we try to release an
1670 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001671 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001672 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001673 }
1674 }
1675 }
1676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 // Geocoder
1678
Nick Pellye0fd6932012-07-11 10:26:13 -07001679 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001680 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001681 return mGeocodeProvider != null;
1682 }
1683
Nick Pellye0fd6932012-07-11 10:26:13 -07001684 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001686 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001687 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001688 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1689 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001691 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 }
1693
Mike Lockwooda55c3212009-04-15 11:10:11 -04001694
Nick Pellye0fd6932012-07-11 10:26:13 -07001695 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001697 double lowerLeftLatitude, double lowerLeftLongitude,
1698 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001699 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001700
1701 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001702 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1703 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1704 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001706 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 }
1708
1709 // Mock Providers
1710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 private void checkMockPermissionsSafe() {
1712 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1713 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1714 if (!allowMocks) {
1715 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1716 }
1717
1718 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1719 PackageManager.PERMISSION_GRANTED) {
1720 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001721 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 }
1723
Nick Pellye0fd6932012-07-11 10:26:13 -07001724 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001725 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 checkMockPermissionsSafe();
1727
Mike Lockwooda4903f22010-02-17 06:42:23 -05001728 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1729 throw new IllegalArgumentException("Cannot mock the passive location provider");
1730 }
1731
Mike Lockwood86328a92009-10-23 08:38:25 -04001732 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001733 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001734 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001735 // remove the real provider if we are replacing GPS or network provider
1736 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001737 || LocationManager.NETWORK_PROVIDER.equals(name)
1738 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001739 LocationProviderInterface p = mProvidersByName.get(name);
1740 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001741 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001742 }
1743 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001744 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1746 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001747 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001748 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001749 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 updateProvidersLocked();
1751 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001752 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 }
1754
Nick Pellye0fd6932012-07-11 10:26:13 -07001755 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 public void removeTestProvider(String provider) {
1757 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001758 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001759 MockProvider mockProvider = mMockProviders.get(provider);
1760 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1762 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001763 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001764 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001765 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001766
1767 // reinstate real provider if available
1768 LocationProviderInterface realProvider = mRealProviders.get(provider);
1769 if (realProvider != null) {
1770 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001771 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001772 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001774 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 }
1776 }
1777
Nick Pellye0fd6932012-07-11 10:26:13 -07001778 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 public void setTestProviderLocation(String provider, Location loc) {
1780 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001781 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001782 MockProvider mockProvider = mMockProviders.get(provider);
1783 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1785 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001786 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1787 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001788 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001789 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 }
1791 }
1792
Nick Pellye0fd6932012-07-11 10:26:13 -07001793 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 public void clearTestProviderLocation(String provider) {
1795 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001796 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001797 MockProvider mockProvider = mMockProviders.get(provider);
1798 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1800 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001801 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 }
1803 }
1804
Nick Pellye0fd6932012-07-11 10:26:13 -07001805 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 public void setTestProviderEnabled(String provider, boolean enabled) {
1807 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001808 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001809 MockProvider mockProvider = mMockProviders.get(provider);
1810 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1812 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001813 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001815 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001816 mEnabledProviders.add(provider);
1817 mDisabledProviders.remove(provider);
1818 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001819 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 mEnabledProviders.remove(provider);
1821 mDisabledProviders.add(provider);
1822 }
1823 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001824 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 }
1826 }
1827
Nick Pellye0fd6932012-07-11 10:26:13 -07001828 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 public void clearTestProviderEnabled(String provider) {
1830 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001831 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001832 MockProvider mockProvider = mMockProviders.get(provider);
1833 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1835 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001836 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 mEnabledProviders.remove(provider);
1838 mDisabledProviders.remove(provider);
1839 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001840 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001841 }
1842 }
1843
Nick Pellye0fd6932012-07-11 10:26:13 -07001844 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001845 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1846 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001847 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001848 MockProvider mockProvider = mMockProviders.get(provider);
1849 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1851 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001852 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 }
1854 }
1855
Nick Pellye0fd6932012-07-11 10:26:13 -07001856 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 public void clearTestProviderStatus(String provider) {
1858 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001859 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001860 MockProvider mockProvider = mMockProviders.get(provider);
1861 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1863 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001864 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 }
1866 }
1867
1868 private void log(String log) {
1869 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001870 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 }
1872 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001873
1874 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1876 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1877 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001878 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 + Binder.getCallingPid()
1880 + ", uid=" + Binder.getCallingUid());
1881 return;
1882 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001883
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001884 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001887 for (Receiver receiver : mReceivers.values()) {
1888 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001891 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1892 pw.println(" " + entry.getKey() + ":");
1893 for (UpdateRecord record : entry.getValue()) {
1894 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895 }
1896 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001898 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1899 String provider = entry.getKey();
1900 Location location = entry.getValue();
1901 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001903
Nick Pellye0fd6932012-07-11 10:26:13 -07001904 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 if (mEnabledProviders.size() > 0) {
1907 pw.println(" Enabled Providers:");
1908 for (String i : mEnabledProviders) {
1909 pw.println(" " + i);
1910 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001912 }
1913 if (mDisabledProviders.size() > 0) {
1914 pw.println(" Disabled Providers:");
1915 for (String i : mDisabledProviders) {
1916 pw.println(" " + i);
1917 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001919 pw.append(" ");
1920 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001921 if (mMockProviders.size() > 0) {
1922 pw.println(" Mock Providers:");
1923 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001924 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925 }
1926 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001927
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001928 pw.append(" fudger: ");
1929 mLocationFudger.dump(fd, pw, args);
1930
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001931 if (args.length > 0 && "short".equals(args[0])) {
1932 return;
1933 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001934 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001935 pw.print(provider.getName() + " Internal State");
1936 if (provider instanceof LocationProviderProxy) {
1937 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1938 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001939 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001940 pw.println(":");
1941 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001942 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 }
1944 }
1945}