blob: a1bd3c5d76cfcf3c0939d3bc53ca3d0825c3942c [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.ContentResolver;
21import android.content.Context;
22import android.content.Intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070023import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.pm.PackageManager.NameNotFoundException;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050026import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070027import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070029import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050030import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070031import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040033import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.ILocationListener;
35import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040036import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.location.Location;
38import android.location.LocationManager;
39import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070040import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.os.Binder;
42import android.os.Bundle;
43import android.os.Handler;
44import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070045import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.Message;
47import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070048import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070050import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070051import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070052import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080055import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
Mike Lockwoode97ae402010-09-29 15:23:46 -040057import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070058import com.android.internal.location.ProviderProperties;
59import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040060import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070061import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040062import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070063import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070064import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040065import com.android.server.location.LocationProviderInterface;
66import com.android.server.location.LocationProviderProxy;
67import com.android.server.location.MockProvider;
68import com.android.server.location.PassiveProvider;
69
70import java.io.FileDescriptor;
71import java.io.PrintWriter;
72import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070073import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040074import java.util.HashMap;
75import java.util.HashSet;
76import java.util.List;
77import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040078import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
80/**
81 * The service class that manages LocationProviders and issues location
82 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 */
Brian Muramatsubb95cb92012-08-29 10:43:21 -070084public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070086 public static final boolean D = false;
87
88 private static final String WAKELOCK_KEY = TAG;
89 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 private static final String ACCESS_FINE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070092 android.Manifest.permission.ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 private static final String ACCESS_COARSE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070094 android.Manifest.permission.ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070096 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070098 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -040099 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700100 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
101
102 private static final String NETWORK_LOCATION_SERVICE_ACTION =
103 "com.android.location.service.v2.NetworkLocationProvider";
104 private static final String FUSED_LOCATION_SERVICE_ACTION =
105 "com.android.location.service.FusedLocationProvider";
106
107 private static final int MSG_LOCATION_CHANGED = 1;
108
Nick Pellyf1be6862012-05-15 10:53:42 -0700109 // Location Providers may sometimes deliver location updates
110 // slightly faster that requested - provide grace period so
111 // we don't unnecessarily filter events that are otherwise on
112 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700113 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700114
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700115 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
116
117 private final Context mContext;
118
119 // used internally for synchronization
120 private final Object mLock = new Object();
121
122 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700123 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700124 private GeofenceManager mGeofenceManager;
125 private PowerManager.WakeLock mWakeLock;
126 private PackageManager mPackageManager;
127 private GeocoderProxy mGeocodeProvider;
128 private IGpsStatusProvider mGpsStatusProvider;
129 private INetInitiatedListener mNetInitiatedListener;
130 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700131 private PassiveProvider mPassiveProvider; // track passive provider for special cases
132 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700133
134 // --- fields below are protected by mWakeLock ---
135 private int mPendingBroadcasts;
136
137 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 // Set of providers that are explicitly enabled
139 private final Set<String> mEnabledProviders = new HashSet<String>();
140
141 // Set of providers that are explicitly disabled
142 private final Set<String> mDisabledProviders = new HashSet<String>();
143
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700144 // Mock (test) providers
145 private final HashMap<String, MockProvider> mMockProviders =
146 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700148 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400149 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700151 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500152 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700153 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400154
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 // real providers, saved here when mocked out
156 private final HashMap<String, LocationProviderInterface> mRealProviders =
157 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700159 // mapping from provider name to provider
160 private final HashMap<String, LocationProviderInterface> mProvidersByName =
161 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700163 // mapping from provider name to all its UpdateRecords
164 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
165 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700166
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 // mapping from provider name to last known location
168 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700170 // all providers that operate over proxy, for authorizing incoming location
171 private final ArrayList<LocationProviderProxy> mProxyProviders =
172 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174 public LocationManagerService(Context context) {
175 super();
176 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800177
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700178 if (D) Log.d(TAG, "Constructed");
179
180 // most startup is deferred until systemReady()
181 }
182
183 public void systemReady() {
184 Thread thread = new Thread(null, this, THREAD_NAME);
185 thread.start();
186 }
187
188 @Override
189 public void run() {
190 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
191 Looper.prepare();
192 mLocationHandler = new LocationWorkerHandler();
193 init();
194 Looper.loop();
195 }
196
197 private void init() {
198 if (D) Log.d(TAG, "init()");
199
200 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
201 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
202 mPackageManager = mContext.getPackageManager();
203
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700204 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
205 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700206 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700207
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700208 synchronized (mLock) {
209 loadProvidersLocked();
210 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700211
Nick Pelly4035f5a2012-08-17 14:43:49 -0700212 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700213
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700214 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700215 mContext.getContentResolver().registerContentObserver(
216 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
217 new ContentObserver(mLocationHandler) {
218 @Override
219 public void onChange(boolean selfChange) {
220 synchronized (mLock) {
221 updateProvidersLocked();
222 }
223 }
224 });
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700225 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700226
227 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700228 }
229
230 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700231 // create a passive location provider, which is always enabled
232 PassiveProvider passiveProvider = new PassiveProvider(this);
233 addProviderLocked(passiveProvider);
234 mEnabledProviders.add(passiveProvider.getName());
235 mPassiveProvider = passiveProvider;
236
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700237 if (GpsLocationProvider.isSupported()) {
238 // Create a gps location provider
239 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
240 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
241 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
242 addProviderLocked(gpsProvider);
243 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
244 }
245
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700246 /*
247 Load package name(s) containing location provider support.
248 These packages can contain services implementing location providers:
249 Geocoder Provider, Network Location Provider, and
250 Fused Location Provider. They will each be searched for
251 service components implementing these providers.
252 The location framework also has support for installation
253 of new location providers at run-time. The new package does not
254 have to be explicitly listed here, however it must have a signature
255 that matches the signature of at least one package on this list.
256 */
257 Resources resources = mContext.getResources();
258 ArrayList<String> providerPackageNames = new ArrayList<String>();
259 String[] pkgs1 = resources.getStringArray(
260 com.android.internal.R.array.config_locationProviderPackageNames);
261 String[] pkgs2 = resources.getStringArray(
262 com.android.internal.R.array.config_overlay_locationProviderPackageNames);
263 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
264 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
265 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
266 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
267
268 // bind to network provider
269 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
270 mContext,
271 LocationManager.NETWORK_PROVIDER,
272 NETWORK_LOCATION_SERVICE_ACTION,
273 providerPackageNames, mLocationHandler);
274 if (networkProvider != null) {
275 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
276 mProxyProviders.add(networkProvider);
277 addProviderLocked(networkProvider);
278 } else {
279 Slog.w(TAG, "no network location provider found");
280 }
281
282 // bind to fused provider
283 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
284 mContext,
285 LocationManager.FUSED_PROVIDER,
286 FUSED_LOCATION_SERVICE_ACTION,
287 providerPackageNames, mLocationHandler);
288 if (fusedLocationProvider != null) {
289 addProviderLocked(fusedLocationProvider);
290 mProxyProviders.add(fusedLocationProvider);
291 mEnabledProviders.add(fusedLocationProvider.getName());
292 } else {
293 Slog.e(TAG, "no fused location provider found",
294 new IllegalStateException("Location service needs a fused location provider"));
295 }
296
297 // bind to geocoder provider
298 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
299 if (mGeocodeProvider == null) {
300 Slog.e(TAG, "no geocoder provider found");
301 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700302 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 /**
305 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
306 * location updates.
307 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700308 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700309 final int mUid; // uid of receiver
310 final int mPid; // pid of receiver
311 final String mPackageName; // package name of receiver
312 final String mPermission; // best permission that receiver has
313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 final ILocationListener mListener;
315 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700317
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400318 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700319
Mike Lockwood48f17512009-04-23 09:12:08 -0700320 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700322 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
323 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700326 if (listener != null) {
327 mKey = listener.asBinder();
328 } else {
329 mKey = intent;
330 }
331 mPermission = checkPermission();
332 mUid = uid;
333 mPid = pid;
334 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 }
336
337 @Override
338 public boolean equals(Object otherObj) {
339 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700340 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 }
342 return false;
343 }
344
345 @Override
346 public int hashCode() {
347 return mKey.hashCode();
348 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 @Override
351 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700352 StringBuilder s = new StringBuilder();
353 s.append("Reciever[");
354 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700356 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700358 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700360 for (String p : mUpdateRecords.keySet()) {
361 s.append(" ").append(mUpdateRecords.get(p).toString());
362 }
363 s.append("]");
364 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 }
366
367 public boolean isListener() {
368 return mListener != null;
369 }
370
371 public boolean isPendingIntent() {
372 return mPendingIntent != null;
373 }
374
375 public ILocationListener getListener() {
376 if (mListener != null) {
377 return mListener;
378 }
379 throw new IllegalStateException("Request for non-existent listener");
380 }
381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
383 if (mListener != null) {
384 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700385 synchronized (this) {
386 // synchronize to ensure incrementPendingBroadcastsLocked()
387 // is called before decrementPendingBroadcasts()
388 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700389 // call this after broadcasting so we do not increment
390 // if we throw an exeption.
391 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700392 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 } catch (RemoteException e) {
394 return false;
395 }
396 } else {
397 Intent statusChanged = new Intent();
398 statusChanged.putExtras(extras);
399 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
400 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700401 synchronized (this) {
402 // synchronize to ensure incrementPendingBroadcastsLocked()
403 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700404 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700405 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700406 // call this after broadcasting so we do not increment
407 // if we throw an exeption.
408 incrementPendingBroadcastsLocked();
409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 } catch (PendingIntent.CanceledException e) {
411 return false;
412 }
413 }
414 return true;
415 }
416
417 public boolean callLocationChangedLocked(Location location) {
418 if (mListener != null) {
419 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700420 synchronized (this) {
421 // synchronize to ensure incrementPendingBroadcastsLocked()
422 // is called before decrementPendingBroadcasts()
423 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700424 // call this after broadcasting so we do not increment
425 // if we throw an exeption.
426 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 } catch (RemoteException e) {
429 return false;
430 }
431 } else {
432 Intent locationChanged = new Intent();
433 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
434 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700435 synchronized (this) {
436 // synchronize to ensure incrementPendingBroadcastsLocked()
437 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700438 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700439 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700440 // call this after broadcasting so we do not increment
441 // if we throw an exeption.
442 incrementPendingBroadcastsLocked();
443 }
444 } catch (PendingIntent.CanceledException e) {
445 return false;
446 }
447 }
448 return true;
449 }
450
451 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
452 if (mListener != null) {
453 try {
454 synchronized (this) {
455 // synchronize to ensure incrementPendingBroadcastsLocked()
456 // is called before decrementPendingBroadcasts()
457 if (enabled) {
458 mListener.onProviderEnabled(provider);
459 } else {
460 mListener.onProviderDisabled(provider);
461 }
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 }
466 } catch (RemoteException e) {
467 return false;
468 }
469 } else {
470 Intent providerIntent = new Intent();
471 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
472 try {
473 synchronized (this) {
474 // synchronize to ensure incrementPendingBroadcastsLocked()
475 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700476 mPendingIntent.send(mContext, 0, providerIntent, 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 } catch (PendingIntent.CanceledException e) {
483 return false;
484 }
485 }
486 return true;
487 }
488
Nick Pellyf1be6862012-05-15 10:53:42 -0700489 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700491 if (D) Log.d(TAG, "Location listener died");
492
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400493 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 removeUpdatesLocked(this);
495 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700496 synchronized (this) {
497 if (mPendingBroadcasts > 0) {
498 LocationManagerService.this.decrementPendingBroadcasts();
499 mPendingBroadcasts = 0;
500 }
501 }
502 }
503
Nick Pellye0fd6932012-07-11 10:26:13 -0700504 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700505 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
506 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400507 synchronized (this) {
508 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700509 }
510 }
511
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400512 // this must be called while synchronized by caller in a synchronized block
513 // containing the sending of the broadcaset
514 private void incrementPendingBroadcastsLocked() {
515 if (mPendingBroadcasts++ == 0) {
516 LocationManagerService.this.incrementPendingBroadcasts();
517 }
518 }
519
520 private void decrementPendingBroadcastsLocked() {
521 if (--mPendingBroadcasts == 0) {
522 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700523 }
524 }
525 }
526
Nick Pellye0fd6932012-07-11 10:26:13 -0700527 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700528 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400529 //Do not use getReceiver here as that will add the ILocationListener to
530 //the receiver list if it is not found. If it is not found then the
531 //LocationListener was removed when it had a pending broadcast and should
532 //not be added back.
533 IBinder binder = listener.asBinder();
534 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700535 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400536 synchronized (receiver) {
537 // so wakelock calls will succeed
538 long identity = Binder.clearCallingIdentity();
539 receiver.decrementPendingBroadcastsLocked();
540 Binder.restoreCallingIdentity(identity);
541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 }
543 }
544
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700545 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400546 mProviders.add(provider);
547 mProvidersByName.put(provider.getName(), provider);
548 }
549
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700550 private void removeProviderLocked(LocationProviderInterface provider) {
551 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400552 mProviders.remove(provider);
553 mProvidersByName.remove(provider.getName());
554 }
555
Mike Lockwood3d12b512009-04-21 23:25:35 -0700556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 private boolean isAllowedBySettingsLocked(String provider) {
558 if (mEnabledProviders.contains(provider)) {
559 return true;
560 }
561 if (mDisabledProviders.contains(provider)) {
562 return false;
563 }
564 // Use system settings
565 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566
Brad Larson8eb3ea62009-12-29 11:47:55 -0600567 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 }
569
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700570 /**
571 * Throw SecurityException if caller has neither COARSE or FINE.
572 * Otherwise, return the best permission.
573 */
574 private String checkPermission() {
575 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
576 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700577 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700578 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
579 PackageManager.PERMISSION_GRANTED) {
580 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700582
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700583 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
Victoria Lease4fab68b2012-09-13 13:20:59 -0700584 " ACCESS_FINE_LOCATION permission");
585 }
586
587 /**
588 * Throw SecurityException if caller lacks permission to use Geofences.
589 */
590 private void checkGeofencePermission() {
591 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
592 PackageManager.PERMISSION_GRANTED) {
593 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 }
596
Victoria Lease8dbb6342012-09-21 16:55:53 -0700597 private boolean isAllowedProviderSafe(String provider) {
598 if (LocationManager.GPS_PROVIDER.equals(provider) ||
599 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
600 // gps and passive providers require FINE permission
601 return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
602 == PackageManager.PERMISSION_GRANTED;
603 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
604 LocationManager.FUSED_PROVIDER.equals(provider)) {
605 // network and fused providers are ok with COARSE or FINE
606 return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
607 == PackageManager.PERMISSION_GRANTED) ||
608 (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
609 == PackageManager.PERMISSION_GRANTED);
610 }
611 return false;
612 }
613
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700614 /**
615 * Returns all providers by name, including passive, but excluding
616 * fused.
617 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700618 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700620 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700622 ArrayList<String> out;
623 synchronized (mLock) {
624 out = new ArrayList<String>(mProviders.size());
625 for (LocationProviderInterface provider : mProviders) {
626 String name = provider.getName();
627 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700628 continue;
629 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 out.add(name);
631 }
632 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700633
634 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 return out;
636 }
637
Mike Lockwood03ca2162010-04-01 08:10:09 -0700638 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700639 * Return all providers by name, that match criteria and are optionally
640 * enabled.
641 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700642 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700643 @Override
644 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700645 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700646 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700647 out = new ArrayList<String>(mProviders.size());
648 for (LocationProviderInterface provider : mProviders) {
649 String name = provider.getName();
650 if (LocationManager.FUSED_PROVIDER.equals(name)) {
651 continue;
652 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700653 if (isAllowedProviderSafe(name)) {
654 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
655 continue;
656 }
657 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
658 name, provider.getProperties(), criteria)) {
659 continue;
660 }
661 out.add(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700662 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700663 }
664 }
665
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700666 if (D) Log.d(TAG, "getProviders()=" + out);
667 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700668 }
669
670 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700671 * Return the name of the best provider given a Criteria object.
672 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700673 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700674 * has been deprecated as well. So this method now uses
675 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700676 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700677 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700678 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700679 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700680
681 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700682 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700683 result = pickBest(providers);
684 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
685 return result;
686 }
687 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700688 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700689 result = pickBest(providers);
690 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
691 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700692 }
693
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700694 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700695 return null;
696 }
697
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700698 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700699 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700700 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700701 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
702 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700703 } else {
704 return providers.get(0);
705 }
706 }
707
Nick Pellye0fd6932012-07-11 10:26:13 -0700708 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700709 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700710 checkPermission();
711
Mike Lockwood03ca2162010-04-01 08:10:09 -0700712 LocationProviderInterface p = mProvidersByName.get(provider);
713 if (p == null) {
714 throw new IllegalArgumentException("provider=" + provider);
715 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700716
717 boolean result = LocationProvider.propertiesMeetCriteria(
718 p.getName(), p.getProperties(), criteria);
719 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
720 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700721 }
722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700724 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400725 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500726 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 boolean isEnabled = p.isEnabled();
728 String name = p.getName();
729 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 if (isEnabled && !shouldBeEnabled) {
731 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700732 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 } else if (!isEnabled && shouldBeEnabled) {
734 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700735 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700737 }
738 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700739 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
740 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 }
742 }
743
744 private void updateProviderListenersLocked(String provider, boolean enabled) {
745 int listeners = 0;
746
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500747 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700748 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749
750 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
753 if (records != null) {
754 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700755 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 UpdateRecord record = records.get(i);
757 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700758 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
759 if (deadReceivers == null) {
760 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 }
Simon Schoar46866572009-06-10 21:12:10 +0200762 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 }
764 listeners++;
765 }
766 }
767
768 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700769 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 removeUpdatesLocked(deadReceivers.get(i));
771 }
772 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700773
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 if (enabled) {
775 p.enable();
776 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700777 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 }
779 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 }
783
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700784 private void applyRequirementsLocked(String provider) {
785 LocationProviderInterface p = mProvidersByName.get(provider);
786 if (p == null) return;
787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700789 WorkSource worksource = new WorkSource();
790 ProviderRequest providerRequest = new ProviderRequest();
791
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700793 for (UpdateRecord record : records) {
794 LocationRequest locationRequest = record.mRequest;
795
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700796 providerRequest.locationRequests.add(locationRequest);
797 if (locationRequest.getInterval() < providerRequest.interval) {
798 providerRequest.reportLocation = true;
799 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700800 }
801 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700802
803 if (providerRequest.reportLocation) {
804 // calculate who to blame for power
805 // This is somewhat arbitrary. We pick a threshold interval
806 // that is slightly higher that the minimum interval, and
807 // spread the blame across all applications with a request
808 // under that threshold.
809 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
810 for (UpdateRecord record : records) {
811 LocationRequest locationRequest = record.mRequest;
812 if (locationRequest.getInterval() <= thresholdInterval) {
813 worksource.add(record.mReceiver.mUid);
814 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700815 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 }
817 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700818
819 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
820 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 }
822
823 private class UpdateRecord {
824 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700825 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400827 Location mLastFixBroadcast;
828 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829
830 /**
831 * Note: must be constructed with lock held.
832 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700833 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700835 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837
838 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
839 if (records == null) {
840 records = new ArrayList<UpdateRecord>();
841 mRecordsByProvider.put(provider, records);
842 }
843 if (!records.contains(this)) {
844 records.add(this);
845 }
846 }
847
848 /**
849 * Method to be called when a record will no longer be used. Calling this multiple times
850 * must have the same effect as calling it once.
851 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700852 void disposeLocked(boolean removeReceiver) {
853 // remove from mRecordsByProvider
854 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
855 if (globalRecords != null) {
856 globalRecords.remove(this);
857 }
858
859 if (!removeReceiver) return; // the caller will handle the rest
860
861 // remove from Receiver#mUpdateRecords
862 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
863 if (receiverRecords != null) {
864 receiverRecords.remove(this.mProvider);
865
866 // and also remove the Receiver if it has no more update records
867 if (removeReceiver && receiverRecords.size() == 0) {
868 removeUpdatesLocked(mReceiver);
869 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400870 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 }
872
873 @Override
874 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700875 StringBuilder s = new StringBuilder();
876 s.append("UpdateRecord[");
877 s.append(mProvider);
878 s.append(' ').append(mReceiver.mPackageName).append('(');
879 s.append(mReceiver.mUid).append(')');
880 s.append(' ').append(mRequest);
881 s.append(']');
882 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 }
885
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700886 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400887 IBinder binder = listener.asBinder();
888 Receiver receiver = mReceivers.get(binder);
889 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700890 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400891 mReceivers.put(binder, receiver);
892
893 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700894 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400895 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800896 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400897 return null;
898 }
899 }
900 return receiver;
901 }
902
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700903 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400904 Receiver receiver = mReceivers.get(intent);
905 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700906 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400907 mReceivers.put(intent, receiver);
908 }
909 return receiver;
910 }
911
Victoria Lease09016ab2012-09-16 12:33:15 -0700912 private boolean isProviderAllowedByCoarsePermission(String provider) {
913 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
914 return true;
915 }
916 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
917 return true;
918 }
919 if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
920 return true;
921 }
922 return false;
923 }
924
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700925 private String checkPermissionAndRequest(LocationRequest request) {
926 String perm = checkPermission();
927
928 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Victoria Lease09016ab2012-09-16 12:33:15 -0700929 if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
930 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
931 }
932 switch (request.getQuality()) {
933 case LocationRequest.ACCURACY_FINE:
934 request.setQuality(LocationRequest.ACCURACY_BLOCK);
935 break;
936 case LocationRequest.POWER_HIGH:
937 request.setQuality(LocationRequest.POWER_LOW);
938 break;
939 }
940 // throttle
941 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
942 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
943 }
944 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
945 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
946 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700947 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700948 // make getFastestInterval() the minimum of interval and fastest interval
949 if (request.getFastestInterval() > request.getInterval()) {
950 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400951 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700952 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400953 }
954
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700955 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700956 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700957 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700958 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700959 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700960 String[] packages = mPackageManager.getPackagesForUid(uid);
961 if (packages == null) {
962 throw new SecurityException("invalid UID " + uid);
963 }
964 for (String pkg : packages) {
965 if (packageName.equals(pkg)) return;
966 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700967 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700968 }
969
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700970 private void checkPendingIntent(PendingIntent intent) {
971 if (intent == null) {
972 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700973 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700974 }
975
976 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
977 int pid, int uid, String packageName) {
978 if (intent == null && listener == null) {
979 throw new IllegalArgumentException("need eiter listener or intent");
980 } else if (intent != null && listener != null) {
981 throw new IllegalArgumentException("cannot register both listener and intent");
982 } else if (intent != null) {
983 checkPendingIntent(intent);
984 return getReceiver(intent, pid, uid, packageName);
985 } else {
986 return getReceiver(listener, pid, uid, packageName);
987 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700988 }
989
Nick Pellye0fd6932012-07-11 10:26:13 -0700990 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700991 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
992 PendingIntent intent, String packageName) {
993 if (request == null) request = DEFAULT_LOCATION_REQUEST;
994 checkPackageName(packageName);
995 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700997 final int pid = Binder.getCallingPid();
998 final int uid = Binder.getCallingUid();
999 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001001 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 long identity = Binder.clearCallingIdentity();
1003 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001004 synchronized (mLock) {
1005 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 } finally {
1008 Binder.restoreCallingIdentity(identity);
1009 }
1010 }
1011
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001012 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1013 int pid, int uid, String packageName) {
1014 // Figure out the provider. Either its explicitly request (legacy use cases), or
1015 // use the fused provider
1016 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1017 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001018 if (name == null) {
1019 throw new IllegalArgumentException("provider name must not be null");
1020 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001021 LocationProviderInterface provider = mProvidersByName.get(name);
1022 if (provider == null) {
1023 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1024 }
1025
1026 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1027 name + " " + request + " from " + packageName + "(" + uid + ")");
1028
1029 UpdateRecord record = new UpdateRecord(name, request, receiver);
1030 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1031 if (oldRecord != null) {
1032 oldRecord.disposeLocked(false);
1033 }
1034
1035 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1036 if (isProviderEnabled) {
1037 applyRequirementsLocked(name);
1038 } else {
1039 // Notify the listener that updates are currently disabled
1040 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 }
1042 }
1043
Nick Pellye0fd6932012-07-11 10:26:13 -07001044 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001045 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1046 String packageName) {
1047 checkPackageName(packageName);
1048 checkPermission();
1049 final int pid = Binder.getCallingPid();
1050 final int uid = Binder.getCallingUid();
1051 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1052
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001053 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001054 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001056 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001057 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001058 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001059 } finally {
1060 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 }
1062 }
1063
1064 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001065 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1066
1067 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1068 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1069 synchronized (receiver) {
1070 if (receiver.mPendingBroadcasts > 0) {
1071 decrementPendingBroadcasts();
1072 receiver.mPendingBroadcasts = 0;
1073 }
1074 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 }
1076
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001077 // Record which providers were associated with this listener
1078 HashSet<String> providers = new HashSet<String>();
1079 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1080 if (oldRecords != null) {
1081 // Call dispose() on the obsolete update records.
1082 for (UpdateRecord record : oldRecords.values()) {
1083 record.disposeLocked(false);
1084 }
1085 // Accumulate providers
1086 providers.addAll(oldRecords.keySet());
1087 }
1088
1089 // update provider
1090 for (String provider : providers) {
1091 // If provider is already disabled, don't need to do anything
1092 if (!isAllowedBySettingsLocked(provider)) {
1093 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 }
1095
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001096 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 }
1098 }
1099
Nick Pellye0fd6932012-07-11 10:26:13 -07001100 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001101 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001102 if (D) Log.d(TAG, "getLastLocation: " + request);
1103 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1104 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001105 checkPackageName(packageName);
1106
1107 if (mBlacklist.isBlacklisted(packageName)) {
1108 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1109 packageName);
1110 return null;
1111 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001112
1113 synchronized (mLock) {
1114 // Figure out the provider. Either its explicitly request (deprecated API's),
1115 // or use the fused provider
1116 String name = request.getProvider();
1117 if (name == null) name = LocationManager.FUSED_PROVIDER;
1118 LocationProviderInterface provider = mProvidersByName.get(name);
1119 if (provider == null) return null;
1120
1121 if (!isAllowedBySettingsLocked(name)) return null;
1122
1123 Location location = mLastLocation.get(name);
Victoria Lease09016ab2012-09-16 12:33:15 -07001124 if (location == null) {
1125 return null;
1126 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001127 if (ACCESS_FINE_LOCATION.equals(perm)) {
1128 return location;
1129 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001130 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1131 if (noGPSLocation != null) {
1132 return mLocationFudger.getOrCreate(noGPSLocation);
1133 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001134 }
1135 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001136 return null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001137 }
1138
1139 @Override
1140 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1141 String packageName) {
1142 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease4fab68b2012-09-13 13:20:59 -07001143 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001144 checkPermissionAndRequest(request);
1145 checkPendingIntent(intent);
1146 checkPackageName(packageName);
1147
1148 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1149
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001150 // geo-fence manager uses the public location API, need to clear identity
1151 int uid = Binder.getCallingUid();
1152 long identity = Binder.clearCallingIdentity();
1153 try {
1154 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1155 } finally {
1156 Binder.restoreCallingIdentity(identity);
1157 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001158 }
1159
1160 @Override
1161 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001162 checkGeofencePermission();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001163 checkPendingIntent(intent);
1164 checkPackageName(packageName);
1165
1166 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1167
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001168 // geo-fence manager uses the public location API, need to clear identity
1169 long identity = Binder.clearCallingIdentity();
1170 try {
1171 mGeofenceManager.removeFence(geofence, intent);
1172 } finally {
1173 Binder.restoreCallingIdentity(identity);
1174 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001175 }
1176
1177
1178 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001180 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 return false;
1182 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001183 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 PackageManager.PERMISSION_GRANTED) {
1185 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1186 }
1187
1188 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001189 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001191 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 return false;
1193 }
1194 return true;
1195 }
1196
Nick Pellye0fd6932012-07-11 10:26:13 -07001197 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001199 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001200 try {
1201 mGpsStatusProvider.removeGpsStatusListener(listener);
1202 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001203 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001204 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001205 }
1206 }
1207
Nick Pellye0fd6932012-07-11 10:26:13 -07001208 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001209 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001210 if (provider == null) {
1211 // throw NullPointerException to remain compatible with previous implementation
1212 throw new NullPointerException();
1213 }
1214
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001215 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001217 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 != PackageManager.PERMISSION_GRANTED)) {
1219 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1220 }
1221
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001222 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001223 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001224 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001225
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001226 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 }
1228 }
1229
Nick Pellye0fd6932012-07-11 10:26:13 -07001230 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001231 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001232 if (Binder.getCallingUid() != Process.myUid()) {
1233 throw new SecurityException(
1234 "calling sendNiResponse from outside of the system is not allowed");
1235 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001236 try {
1237 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001238 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001239 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001240 return false;
1241 }
1242 }
1243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001245 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001246 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 * accessed by the caller
1248 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001249 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001250 public ProviderProperties getProviderProperties(String provider) {
1251 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001253 LocationProviderInterface p;
1254 synchronized (mLock) {
1255 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 }
1257
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001258 if (p == null) return null;
1259 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 }
1261
Nick Pellye0fd6932012-07-11 10:26:13 -07001262 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001264 checkPermission();
1265 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1266
1267 synchronized (mLock) {
1268 LocationProviderInterface p = mProvidersByName.get(provider);
1269 if (p == null) return false;
1270
1271 return isAllowedBySettingsLocked(provider);
1272 }
1273 }
1274
1275 private void checkCallerIsProvider() {
1276 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1277 == PackageManager.PERMISSION_GRANTED) {
1278 return;
1279 }
1280
1281 // Previously we only used the INSTALL_LOCATION_PROVIDER
1282 // check. But that is system or signature
1283 // protection level which is not flexible enough for
1284 // providers installed oustide the system image. So
1285 // also allow providers with a UID matching the
1286 // currently bound package name
1287
1288 int uid = Binder.getCallingUid();
1289
1290 if (mGeocodeProvider != null) {
1291 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1292 }
1293 for (LocationProviderProxy proxy : mProxyProviders) {
1294 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1295 }
1296 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1297 "or UID of a currently bound location provider");
1298 }
1299
1300 private boolean doesPackageHaveUid(int uid, String packageName) {
1301 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 return false;
1303 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001304 try {
1305 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1306 if (appInfo.uid != uid) {
1307 return false;
1308 }
1309 } catch (NameNotFoundException e) {
1310 return false;
1311 }
1312 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 }
1314
Nick Pellye0fd6932012-07-11 10:26:13 -07001315 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001316 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001317 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001318
Nick Pelly2eeeec22012-07-18 13:13:37 -07001319 if (!location.isComplete()) {
1320 Log.w(TAG, "Dropping incomplete location: " + location);
1321 return;
1322 }
1323
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001324 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1325 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001326 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001327 mLocationHandler.sendMessageAtFrontOfQueue(m);
1328 }
1329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330
1331 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1332 // Always broadcast the first update
1333 if (lastLoc == null) {
1334 return true;
1335 }
1336
Nick Pellyf1be6862012-05-15 10:53:42 -07001337 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001338 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001339 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001340 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 return false;
1342 }
1343
1344 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001345 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 if (minDistance > 0.0) {
1347 if (loc.distanceTo(lastLoc) <= minDistance) {
1348 return false;
1349 }
1350 }
1351
1352 return true;
1353 }
1354
Mike Lockwooda4903f22010-02-17 06:42:23 -05001355 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001356 if (D) Log.d(TAG, "incoming location: " + location);
1357
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001358 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001359 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001361 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001363 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001364 if (p == null) return;
1365
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001366 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001367 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1368 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001369 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001370 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001371 lastLocation = new Location(provider);
1372 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001373 } else {
1374 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1375 if (noGPSLocation == null && lastNoGPSLocation != null) {
1376 // New location has no no-GPS location: adopt last no-GPS location. This is set
1377 // directly into location because we do not want to notify COARSE clients.
1378 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1379 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001380 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001381 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001382
Victoria Lease09016ab2012-09-16 12:33:15 -07001383 // Fetch coarse location
1384 Location coarseLocation = null;
1385 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1386 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1387 }
1388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 // Fetch latest status update time
1390 long newStatusUpdateTime = p.getStatusUpdateTime();
1391
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001392 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 Bundle extras = new Bundle();
1394 int status = p.getStatus(extras);
1395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001397 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001400 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001402 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001403
1404 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1405 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1406 receiver.mPackageName);
1407 continue;
1408 }
1409
Victoria Lease09016ab2012-09-16 12:33:15 -07001410 Location notifyLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001411 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001412 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001413 } else {
Victoria Lease09016ab2012-09-16 12:33:15 -07001414 notifyLocation = coarseLocation; // use coarse location if available
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001415 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001416 if (notifyLocation != null) {
1417 Location lastLoc = r.mLastFixBroadcast;
1418 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1419 if (lastLoc == null) {
1420 lastLoc = new Location(notifyLocation);
1421 r.mLastFixBroadcast = lastLoc;
1422 } else {
1423 lastLoc.set(notifyLocation);
1424 }
1425 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1426 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1427 receiverDead = true;
1428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 }
1430 }
1431
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001432 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001434 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001436 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001438 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001439 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001440 }
1441 }
1442
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001443 // track expired records
1444 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1445 if (deadUpdateRecords == null) {
1446 deadUpdateRecords = new ArrayList<UpdateRecord>();
1447 }
1448 deadUpdateRecords.add(r);
1449 }
1450 // track dead receivers
1451 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001452 if (deadReceivers == null) {
1453 deadReceivers = new ArrayList<Receiver>();
1454 }
1455 if (!deadReceivers.contains(receiver)) {
1456 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 }
1458 }
1459 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001460
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001461 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001463 for (Receiver receiver : deadReceivers) {
1464 removeUpdatesLocked(receiver);
1465 }
1466 }
1467 if (deadUpdateRecords != null) {
1468 for (UpdateRecord r : deadUpdateRecords) {
1469 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 }
1471 }
1472 }
1473
1474 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001475 @Override
1476 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001477 switch (msg.what) {
1478 case MSG_LOCATION_CHANGED:
1479 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1480 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 }
1482 }
1483 }
1484
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001485 private void handleLocationChanged(Location location, boolean passive) {
1486 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001487
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001488 if (!passive) {
1489 // notify passive provider of the new location
1490 mPassiveProvider.updateLocation(location);
1491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001493 synchronized (mLock) {
1494 if (isAllowedBySettingsLocked(provider)) {
1495 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499
Mike Lockwoode97ae402010-09-29 15:23:46 -04001500 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1501 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001502 public void onPackageDisappeared(String packageName, int reason) {
1503 // remove all receivers associated with this package name
1504 synchronized (mLock) {
1505 ArrayList<Receiver> deadReceivers = null;
1506
1507 for (Receiver receiver : mReceivers.values()) {
1508 if (receiver.mPackageName.equals(packageName)) {
1509 if (deadReceivers == null) {
1510 deadReceivers = new ArrayList<Receiver>();
1511 }
1512 deadReceivers.add(receiver);
1513 }
1514 }
1515
1516 // perform removal outside of mReceivers loop
1517 if (deadReceivers != null) {
1518 for (Receiver receiver : deadReceivers) {
1519 removeUpdatesLocked(receiver);
1520 }
1521 }
1522 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001523 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001524 };
1525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 // Wake locks
1527
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001528 private void incrementPendingBroadcasts() {
1529 synchronized (mWakeLock) {
1530 if (mPendingBroadcasts++ == 0) {
1531 try {
1532 mWakeLock.acquire();
1533 log("Acquired wakelock");
1534 } catch (Exception e) {
1535 // This is to catch a runtime exception thrown when we try to release an
1536 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001537 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001538 }
1539 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001540 }
1541 }
1542
1543 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001544 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001545 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001546 try {
1547 // Release wake lock
1548 if (mWakeLock.isHeld()) {
1549 mWakeLock.release();
1550 log("Released wakelock");
1551 } else {
1552 log("Can't release wakelock again!");
1553 }
1554 } catch (Exception e) {
1555 // This is to catch a runtime exception thrown when we try to release an
1556 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001557 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001558 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001559 }
1560 }
1561 }
1562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 // Geocoder
1564
Nick Pellye0fd6932012-07-11 10:26:13 -07001565 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001566 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001567 return mGeocodeProvider != null;
1568 }
1569
Nick Pellye0fd6932012-07-11 10:26:13 -07001570 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001572 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001573 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001574 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1575 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001577 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 }
1579
Mike Lockwooda55c3212009-04-15 11:10:11 -04001580
Nick Pellye0fd6932012-07-11 10:26:13 -07001581 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001583 double lowerLeftLatitude, double lowerLeftLongitude,
1584 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001585 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001586
1587 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001588 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1589 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1590 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001592 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 }
1594
1595 // Mock Providers
1596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 private void checkMockPermissionsSafe() {
1598 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1599 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1600 if (!allowMocks) {
1601 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1602 }
1603
1604 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1605 PackageManager.PERMISSION_GRANTED) {
1606 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001607 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 }
1609
Nick Pellye0fd6932012-07-11 10:26:13 -07001610 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001611 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 checkMockPermissionsSafe();
1613
Mike Lockwooda4903f22010-02-17 06:42:23 -05001614 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1615 throw new IllegalArgumentException("Cannot mock the passive location provider");
1616 }
1617
Mike Lockwood86328a92009-10-23 08:38:25 -04001618 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001619 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001620 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001621 // remove the real provider if we are replacing GPS or network provider
1622 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001623 || LocationManager.NETWORK_PROVIDER.equals(name)
1624 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001625 LocationProviderInterface p = mProvidersByName.get(name);
1626 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001627 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001628 }
1629 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001630 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1632 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001633 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001634 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001635 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 updateProvidersLocked();
1637 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001638 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 }
1640
Nick Pellye0fd6932012-07-11 10:26:13 -07001641 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 public void removeTestProvider(String provider) {
1643 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001644 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001645 MockProvider mockProvider = mMockProviders.get(provider);
1646 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1648 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001649 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001650 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001651 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001652
1653 // reinstate real provider if available
1654 LocationProviderInterface realProvider = mRealProviders.get(provider);
1655 if (realProvider != null) {
1656 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001657 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001658 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001660 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 }
1662 }
1663
Nick Pellye0fd6932012-07-11 10:26:13 -07001664 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 public void setTestProviderLocation(String provider, Location loc) {
1666 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001667 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001668 MockProvider mockProvider = mMockProviders.get(provider);
1669 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1671 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001672 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1673 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001674 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001675 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 }
1677 }
1678
Nick Pellye0fd6932012-07-11 10:26:13 -07001679 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 public void clearTestProviderLocation(String provider) {
1681 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001682 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001683 MockProvider mockProvider = mMockProviders.get(provider);
1684 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1686 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001687 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 }
1689 }
1690
Nick Pellye0fd6932012-07-11 10:26:13 -07001691 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 public void setTestProviderEnabled(String provider, boolean enabled) {
1693 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001694 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001695 MockProvider mockProvider = mMockProviders.get(provider);
1696 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1698 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001699 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001701 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 mEnabledProviders.add(provider);
1703 mDisabledProviders.remove(provider);
1704 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001705 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 mEnabledProviders.remove(provider);
1707 mDisabledProviders.add(provider);
1708 }
1709 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001710 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 }
1712 }
1713
Nick Pellye0fd6932012-07-11 10:26:13 -07001714 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 public void clearTestProviderEnabled(String provider) {
1716 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001717 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001718 MockProvider mockProvider = mMockProviders.get(provider);
1719 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1721 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001722 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 mEnabledProviders.remove(provider);
1724 mDisabledProviders.remove(provider);
1725 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001726 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 }
1728 }
1729
Nick Pellye0fd6932012-07-11 10:26:13 -07001730 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1732 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001733 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001734 MockProvider mockProvider = mMockProviders.get(provider);
1735 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1737 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001738 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 }
1740 }
1741
Nick Pellye0fd6932012-07-11 10:26:13 -07001742 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 public void clearTestProviderStatus(String provider) {
1744 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001745 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001746 MockProvider mockProvider = mMockProviders.get(provider);
1747 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1749 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001750 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 }
1752 }
1753
1754 private void log(String log) {
1755 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001756 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 }
1758 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001759
1760 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1762 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1763 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001764 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 + Binder.getCallingPid()
1766 + ", uid=" + Binder.getCallingUid());
1767 return;
1768 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001769
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001770 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001773 for (Receiver receiver : mReceivers.values()) {
1774 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001777 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1778 pw.println(" " + entry.getKey() + ":");
1779 for (UpdateRecord record : entry.getValue()) {
1780 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 }
1782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001784 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1785 String provider = entry.getKey();
1786 Location location = entry.getValue();
1787 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001788 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001789
Nick Pellye0fd6932012-07-11 10:26:13 -07001790 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001791
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 if (mEnabledProviders.size() > 0) {
1793 pw.println(" Enabled Providers:");
1794 for (String i : mEnabledProviders) {
1795 pw.println(" " + i);
1796 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 }
1799 if (mDisabledProviders.size() > 0) {
1800 pw.println(" Disabled Providers:");
1801 for (String i : mDisabledProviders) {
1802 pw.println(" " + i);
1803 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001805 pw.append(" ");
1806 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 if (mMockProviders.size() > 0) {
1808 pw.println(" Mock Providers:");
1809 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001810 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 }
1812 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001813
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001814 pw.append(" fudger: ");
1815 mLocationFudger.dump(fd, pw, args);
1816
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001817 if (args.length > 0 && "short".equals(args[0])) {
1818 return;
1819 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001820 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001821 pw.print(provider.getName() + " Internal State");
1822 if (provider instanceof LocationProviderProxy) {
1823 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1824 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001825 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001826 pw.println(":");
1827 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001828 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 }
1830 }
1831}