blob: 5993f327cd4aa0d5e4961ce221fd0fe01ff4193a [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;
Mike Lockwood9637d472009-04-02 21:41:57 -070020import android.content.ContentQueryMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070027import android.content.pm.PackageManager.NameNotFoundException;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050028import android.content.res.Resources;
Mike Lockwood9637d472009-04-02 21:41:57 -070029import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070031import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050032import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070033import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040035import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.location.ILocationListener;
37import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040038import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.Location;
40import android.location.LocationManager;
41import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070042import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.net.ConnectivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.Binder;
45import android.os.Bundle;
46import android.os.Handler;
47import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070048import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.Message;
50import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070051import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070053import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070054import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070055import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.provider.Settings;
Nick Pellye0fd6932012-07-11 10:26:13 -070057import android.provider.Settings.NameValueTable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080059import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060
Mike Lockwoode97ae402010-09-29 15:23:46 -040061import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070062import com.android.internal.location.ProviderProperties;
63import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040064import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070065import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040066import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070067import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070068import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040069import com.android.server.location.LocationProviderInterface;
70import com.android.server.location.LocationProviderProxy;
71import com.android.server.location.MockProvider;
72import com.android.server.location.PassiveProvider;
73
74import java.io.FileDescriptor;
75import java.io.PrintWriter;
76import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070077import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040078import java.util.HashMap;
79import java.util.HashSet;
80import java.util.List;
81import java.util.Map;
82import java.util.Observable;
83import java.util.Observer;
84import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
86/**
87 * The service class that manages LocationProviders and issues location
88 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -070090public class LocationManagerService extends ILocationManager.Stub implements Observer, Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070092 public static final boolean D = false;
93
94 private static final String WAKELOCK_KEY = TAG;
95 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 private static final String ACCESS_FINE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -070098 android.Manifest.permission.ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 private static final String ACCESS_COARSE_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700100 android.Manifest.permission.ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700102 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700104 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400105 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700106 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
107
108 private static final String NETWORK_LOCATION_SERVICE_ACTION =
109 "com.android.location.service.v2.NetworkLocationProvider";
110 private static final String FUSED_LOCATION_SERVICE_ACTION =
111 "com.android.location.service.FusedLocationProvider";
112
113 private static final int MSG_LOCATION_CHANGED = 1;
114
Nick Pellyf1be6862012-05-15 10:53:42 -0700115 // Location Providers may sometimes deliver location updates
116 // slightly faster that requested - provide grace period so
117 // we don't unnecessarily filter events that are otherwise on
118 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700119 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700120
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700121 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
122
123 private final Context mContext;
124
125 // used internally for synchronization
126 private final Object mLock = new Object();
127
128 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700129 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700130 private GeofenceManager mGeofenceManager;
131 private PowerManager.WakeLock mWakeLock;
132 private PackageManager mPackageManager;
133 private GeocoderProxy mGeocodeProvider;
134 private IGpsStatusProvider mGpsStatusProvider;
135 private INetInitiatedListener mNetInitiatedListener;
136 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700137 private PassiveProvider mPassiveProvider; // track passive provider for special cases
138 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700139
140 // --- fields below are protected by mWakeLock ---
141 private int mPendingBroadcasts;
142
143 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 // Set of providers that are explicitly enabled
145 private final Set<String> mEnabledProviders = new HashSet<String>();
146
147 // Set of providers that are explicitly disabled
148 private final Set<String> mDisabledProviders = new HashSet<String>();
149
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700150 // Mock (test) providers
151 private final HashMap<String, MockProvider> mMockProviders =
152 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700154 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400155 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700157 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500158 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700159 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400160
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700161 // real providers, saved here when mocked out
162 private final HashMap<String, LocationProviderInterface> mRealProviders =
163 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700165 // mapping from provider name to provider
166 private final HashMap<String, LocationProviderInterface> mProvidersByName =
167 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // mapping from provider name to all its UpdateRecords
170 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
171 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700172
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700173 // mapping from provider name to last known location
174 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700176 // all providers that operate over proxy, for authorizing incoming location
177 private final ArrayList<LocationProviderProxy> mProxyProviders =
178 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700180 public LocationManagerService(Context context) {
181 super();
182 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800183
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700184 if (D) Log.d(TAG, "Constructed");
185
186 // most startup is deferred until systemReady()
187 }
188
189 public void systemReady() {
190 Thread thread = new Thread(null, this, THREAD_NAME);
191 thread.start();
192 }
193
194 @Override
195 public void run() {
196 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
197 Looper.prepare();
198 mLocationHandler = new LocationWorkerHandler();
199 init();
200 Looper.loop();
201 }
202
203 private void init() {
204 if (D) Log.d(TAG, "init()");
205
206 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
207 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
208 mPackageManager = mContext.getPackageManager();
209
210 synchronized (mLock) {
211 loadProvidersLocked();
212 }
Nick Pelly4035f5a2012-08-17 14:43:49 -0700213 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
214 mBlacklist.init();
215 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700216 mLocationFudger = new LocationFudger();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700217
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700218 // listen for settings changes
219 ContentResolver resolver = mContext.getContentResolver();
220 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
221 "(" + NameValueTable.NAME + "=?)",
222 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, null);
223 ContentQueryMap query = new ContentQueryMap(settingsCursor, NameValueTable.NAME, true,
224 mLocationHandler);
225 settingsCursor.close();
226 query.addObserver(this);
227 mPackageMonitor.register(mContext, Looper.myLooper(), true);
228 }
229
230 private void loadProvidersLocked() {
231 if (GpsLocationProvider.isSupported()) {
232 // Create a gps location provider
233 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
234 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
235 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
236 addProviderLocked(gpsProvider);
237 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
238 }
239
240 // create a passive location provider, which is always enabled
241 PassiveProvider passiveProvider = new PassiveProvider(this);
242 addProviderLocked(passiveProvider);
243 mEnabledProviders.add(passiveProvider.getName());
244 mPassiveProvider = passiveProvider;
245
246 /*
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 }
302
303 updateProvidersLocked();
304 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 /**
307 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
308 * location updates.
309 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700310 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700311 final int mUid; // uid of receiver
312 final int mPid; // pid of receiver
313 final String mPackageName; // package name of receiver
314 final String mPermission; // best permission that receiver has
315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 final ILocationListener mListener;
317 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700319
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400320 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700321
Mike Lockwood48f17512009-04-23 09:12:08 -0700322 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700324 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
325 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700328 if (listener != null) {
329 mKey = listener.asBinder();
330 } else {
331 mKey = intent;
332 }
333 mPermission = checkPermission();
334 mUid = uid;
335 mPid = pid;
336 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 }
338
339 @Override
340 public boolean equals(Object otherObj) {
341 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700342 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 }
344 return false;
345 }
346
347 @Override
348 public int hashCode() {
349 return mKey.hashCode();
350 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 @Override
353 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700354 StringBuilder s = new StringBuilder();
355 s.append("Reciever[");
356 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700358 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700360 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700362 for (String p : mUpdateRecords.keySet()) {
363 s.append(" ").append(mUpdateRecords.get(p).toString());
364 }
365 s.append("]");
366 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 }
368
369 public boolean isListener() {
370 return mListener != null;
371 }
372
373 public boolean isPendingIntent() {
374 return mPendingIntent != null;
375 }
376
377 public ILocationListener getListener() {
378 if (mListener != null) {
379 return mListener;
380 }
381 throw new IllegalStateException("Request for non-existent listener");
382 }
383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
385 if (mListener != null) {
386 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700387 synchronized (this) {
388 // synchronize to ensure incrementPendingBroadcastsLocked()
389 // is called before decrementPendingBroadcasts()
390 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700391 // call this after broadcasting so we do not increment
392 // if we throw an exeption.
393 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700394 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 } catch (RemoteException e) {
396 return false;
397 }
398 } else {
399 Intent statusChanged = new Intent();
400 statusChanged.putExtras(extras);
401 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
402 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700403 synchronized (this) {
404 // synchronize to ensure incrementPendingBroadcastsLocked()
405 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700406 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700407 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700408 // call this after broadcasting so we do not increment
409 // if we throw an exeption.
410 incrementPendingBroadcastsLocked();
411 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 } catch (PendingIntent.CanceledException e) {
413 return false;
414 }
415 }
416 return true;
417 }
418
419 public boolean callLocationChangedLocked(Location location) {
420 if (mListener != null) {
421 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700422 synchronized (this) {
423 // synchronize to ensure incrementPendingBroadcastsLocked()
424 // is called before decrementPendingBroadcasts()
425 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700426 // call this after broadcasting so we do not increment
427 // if we throw an exeption.
428 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 } catch (RemoteException e) {
431 return false;
432 }
433 } else {
434 Intent locationChanged = new Intent();
435 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
436 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700437 synchronized (this) {
438 // synchronize to ensure incrementPendingBroadcastsLocked()
439 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700440 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700441 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700442 // call this after broadcasting so we do not increment
443 // if we throw an exeption.
444 incrementPendingBroadcastsLocked();
445 }
446 } catch (PendingIntent.CanceledException e) {
447 return false;
448 }
449 }
450 return true;
451 }
452
453 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
454 if (mListener != null) {
455 try {
456 synchronized (this) {
457 // synchronize to ensure incrementPendingBroadcastsLocked()
458 // is called before decrementPendingBroadcasts()
459 if (enabled) {
460 mListener.onProviderEnabled(provider);
461 } else {
462 mListener.onProviderDisabled(provider);
463 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700464 // call this after broadcasting so we do not increment
465 // if we throw an exeption.
466 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700467 }
468 } catch (RemoteException e) {
469 return false;
470 }
471 } else {
472 Intent providerIntent = new Intent();
473 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
474 try {
475 synchronized (this) {
476 // synchronize to ensure incrementPendingBroadcastsLocked()
477 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700478 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700479 mPermission);
Mike Lockwood48f17512009-04-23 09:12:08 -0700480 // call this after broadcasting so we do not increment
481 // if we throw an exeption.
482 incrementPendingBroadcastsLocked();
483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 } catch (PendingIntent.CanceledException e) {
485 return false;
486 }
487 }
488 return true;
489 }
490
Nick Pellyf1be6862012-05-15 10:53:42 -0700491 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700493 if (D) Log.d(TAG, "Location listener died");
494
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400495 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 removeUpdatesLocked(this);
497 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700498 synchronized (this) {
499 if (mPendingBroadcasts > 0) {
500 LocationManagerService.this.decrementPendingBroadcasts();
501 mPendingBroadcasts = 0;
502 }
503 }
504 }
505
Nick Pellye0fd6932012-07-11 10:26:13 -0700506 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700507 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
508 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400509 synchronized (this) {
510 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700511 }
512 }
513
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400514 // this must be called while synchronized by caller in a synchronized block
515 // containing the sending of the broadcaset
516 private void incrementPendingBroadcastsLocked() {
517 if (mPendingBroadcasts++ == 0) {
518 LocationManagerService.this.incrementPendingBroadcasts();
519 }
520 }
521
522 private void decrementPendingBroadcastsLocked() {
523 if (--mPendingBroadcasts == 0) {
524 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700525 }
526 }
527 }
528
Nick Pellye0fd6932012-07-11 10:26:13 -0700529 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700530 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400531 //Do not use getReceiver here as that will add the ILocationListener to
532 //the receiver list if it is not found. If it is not found then the
533 //LocationListener was removed when it had a pending broadcast and should
534 //not be added back.
535 IBinder binder = listener.asBinder();
536 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700537 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400538 synchronized (receiver) {
539 // so wakelock calls will succeed
540 long identity = Binder.clearCallingIdentity();
541 receiver.decrementPendingBroadcastsLocked();
542 Binder.restoreCallingIdentity(identity);
543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 }
545 }
546
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700547 /** Settings Observer callback */
548 @Override
549 public void update(Observable o, Object arg) {
550 synchronized (mLock) {
551 updateProvidersLocked();
Mike Lockwood9637d472009-04-02 21:41:57 -0700552 }
553 }
554
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700555 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400556 mProviders.add(provider);
557 mProvidersByName.put(provider.getName(), provider);
558 }
559
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700560 private void removeProviderLocked(LocationProviderInterface provider) {
561 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400562 mProviders.remove(provider);
563 mProvidersByName.remove(provider.getName());
564 }
565
Mike Lockwood3d12b512009-04-21 23:25:35 -0700566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 private boolean isAllowedBySettingsLocked(String provider) {
568 if (mEnabledProviders.contains(provider)) {
569 return true;
570 }
571 if (mDisabledProviders.contains(provider)) {
572 return false;
573 }
574 // Use system settings
575 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576
Brad Larson8eb3ea62009-12-29 11:47:55 -0600577 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 }
579
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700580 /**
581 * Throw SecurityException if caller has neither COARSE or FINE.
582 * Otherwise, return the best permission.
583 */
584 private String checkPermission() {
585 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
586 PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700587 return ACCESS_FINE_LOCATION;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700588 } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
589 PackageManager.PERMISSION_GRANTED) {
590 return ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700592
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700593 throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
594 "ACCESS_FINE_LOCATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 }
596
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700597 /**
598 * Returns all providers by name, including passive, but excluding
599 * fused.
600 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700601 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700603 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700605 ArrayList<String> out;
606 synchronized (mLock) {
607 out = new ArrayList<String>(mProviders.size());
608 for (LocationProviderInterface provider : mProviders) {
609 String name = provider.getName();
610 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700611 continue;
612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 out.add(name);
614 }
615 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700616
617 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 return out;
619 }
620
Mike Lockwood03ca2162010-04-01 08:10:09 -0700621 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700622 * Return all providers by name, that match criteria and are optionally
623 * enabled.
624 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700625 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700626 @Override
627 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
628 checkPermission();
Mike Lockwood03ca2162010-04-01 08:10:09 -0700629
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700630 ArrayList<String> out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700631 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700632 out = new ArrayList<String>(mProviders.size());
633 for (LocationProviderInterface provider : mProviders) {
634 String name = provider.getName();
635 if (LocationManager.FUSED_PROVIDER.equals(name)) {
636 continue;
637 }
638 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
639 continue;
640 }
641 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
642 name, provider.getProperties(), criteria)) {
643 continue;
644 }
645 out.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700646 }
647 }
648
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700649 if (D) Log.d(TAG, "getProviders()=" + out);
650 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700651 }
652
653 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700654 * Return the name of the best provider given a Criteria object.
655 * This method has been deprecated from the public API,
656 * and the whole LoactionProvider (including #meetsCriteria)
657 * has been deprecated as well. So this method now uses
658 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700659 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700660 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700661 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700662 String result = null;
663 checkPermission();
664
665 List<String> providers = getProviders(criteria, enabledOnly);
666 if (providers.size() < 1) {
667 result = pickBest(providers);
668 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
669 return result;
670 }
671 providers = getProviders(null, enabledOnly);
672 if (providers.size() >= 1) {
673 result = pickBest(providers);
674 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
675 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700676 }
677
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700678 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700679 return null;
680 }
681
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700682 private String pickBest(List<String> providers) {
683 if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
684 return LocationManager.NETWORK_PROVIDER;
685 } else if (providers.contains(LocationManager.GPS_PROVIDER)) {
686 return LocationManager.GPS_PROVIDER;
687 } else {
688 return providers.get(0);
689 }
690 }
691
Nick Pellye0fd6932012-07-11 10:26:13 -0700692 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700693 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700694 checkPermission();
695
Mike Lockwood03ca2162010-04-01 08:10:09 -0700696 LocationProviderInterface p = mProvidersByName.get(provider);
697 if (p == null) {
698 throw new IllegalArgumentException("provider=" + provider);
699 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700700
701 boolean result = LocationProvider.propertiesMeetCriteria(
702 p.getName(), p.getProperties(), criteria);
703 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
704 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700705 }
706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700708 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400709 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500710 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 boolean isEnabled = p.isEnabled();
712 String name = p.getName();
713 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 if (isEnabled && !shouldBeEnabled) {
715 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700716 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 } else if (!isEnabled && shouldBeEnabled) {
718 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700719 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700721 }
722 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700723 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
724 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 }
726 }
727
728 private void updateProviderListenersLocked(String provider, boolean enabled) {
729 int listeners = 0;
730
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500731 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700732 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733
734 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
737 if (records != null) {
738 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700739 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 UpdateRecord record = records.get(i);
741 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700742 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
743 if (deadReceivers == null) {
744 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 }
Simon Schoar46866572009-06-10 21:12:10 +0200746 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 }
748 listeners++;
749 }
750 }
751
752 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700753 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 removeUpdatesLocked(deadReceivers.get(i));
755 }
756 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700757
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 if (enabled) {
759 p.enable();
760 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700761 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 }
763 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 }
767
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700768 private void applyRequirementsLocked(String provider) {
769 LocationProviderInterface p = mProvidersByName.get(provider);
770 if (p == null) return;
771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700773 WorkSource worksource = new WorkSource();
774 ProviderRequest providerRequest = new ProviderRequest();
775
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700777 for (UpdateRecord record : records) {
778 LocationRequest locationRequest = record.mRequest;
779
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700780 providerRequest.locationRequests.add(locationRequest);
781 if (locationRequest.getInterval() < providerRequest.interval) {
782 providerRequest.reportLocation = true;
783 providerRequest.interval = locationRequest.getInterval();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700784 }
785 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700786
787 if (providerRequest.reportLocation) {
788 // calculate who to blame for power
789 // This is somewhat arbitrary. We pick a threshold interval
790 // that is slightly higher that the minimum interval, and
791 // spread the blame across all applications with a request
792 // under that threshold.
793 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
794 for (UpdateRecord record : records) {
795 LocationRequest locationRequest = record.mRequest;
796 if (locationRequest.getInterval() <= thresholdInterval) {
797 worksource.add(record.mReceiver.mUid);
798 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700799 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 }
801 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700802
803 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
804 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 }
806
807 private class UpdateRecord {
808 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700809 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400811 Location mLastFixBroadcast;
812 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813
814 /**
815 * Note: must be constructed with lock held.
816 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700817 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700819 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821
822 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
823 if (records == null) {
824 records = new ArrayList<UpdateRecord>();
825 mRecordsByProvider.put(provider, records);
826 }
827 if (!records.contains(this)) {
828 records.add(this);
829 }
830 }
831
832 /**
833 * Method to be called when a record will no longer be used. Calling this multiple times
834 * must have the same effect as calling it once.
835 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700836 void disposeLocked(boolean removeReceiver) {
837 // remove from mRecordsByProvider
838 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
839 if (globalRecords != null) {
840 globalRecords.remove(this);
841 }
842
843 if (!removeReceiver) return; // the caller will handle the rest
844
845 // remove from Receiver#mUpdateRecords
846 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
847 if (receiverRecords != null) {
848 receiverRecords.remove(this.mProvider);
849
850 // and also remove the Receiver if it has no more update records
851 if (removeReceiver && receiverRecords.size() == 0) {
852 removeUpdatesLocked(mReceiver);
853 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 }
856
857 @Override
858 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700859 StringBuilder s = new StringBuilder();
860 s.append("UpdateRecord[");
861 s.append(mProvider);
862 s.append(' ').append(mReceiver.mPackageName).append('(');
863 s.append(mReceiver.mUid).append(')');
864 s.append(' ').append(mRequest);
865 s.append(']');
866 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 }
869
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700870 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400871 IBinder binder = listener.asBinder();
872 Receiver receiver = mReceivers.get(binder);
873 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700874 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400875 mReceivers.put(binder, receiver);
876
877 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700878 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400879 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800880 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400881 return null;
882 }
883 }
884 return receiver;
885 }
886
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700887 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400888 Receiver receiver = mReceivers.get(intent);
889 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700890 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400891 mReceivers.put(intent, receiver);
892 }
893 return receiver;
894 }
895
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700896 private String checkPermissionAndRequest(LocationRequest request) {
897 String perm = checkPermission();
898
899 if (ACCESS_COARSE_LOCATION.equals(perm)) {
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700900 switch (request.getQuality()) {
901 case LocationRequest.ACCURACY_FINE:
902 request.setQuality(LocationRequest.ACCURACY_BLOCK);
903 break;
904 case LocationRequest.POWER_HIGH:
905 request.setQuality(LocationRequest.POWER_LOW);
906 break;
907 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700908 // throttle
909 if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
910 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
911 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700912 if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
913 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
914 }
915 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -0700916 // make getFastestInterval() the minimum of interval and fastest interval
917 if (request.getFastestInterval() > request.getInterval()) {
918 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400919 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700920 return perm;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400921 }
922
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700923 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -0700924 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700925 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700926 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700927 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -0700928 String[] packages = mPackageManager.getPackagesForUid(uid);
929 if (packages == null) {
930 throw new SecurityException("invalid UID " + uid);
931 }
932 for (String pkg : packages) {
933 if (packageName.equals(pkg)) return;
934 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700935 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -0700936 }
937
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700938 private void checkPendingIntent(PendingIntent intent) {
939 if (intent == null) {
940 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700941 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700942 }
943
944 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
945 int pid, int uid, String packageName) {
946 if (intent == null && listener == null) {
947 throw new IllegalArgumentException("need eiter listener or intent");
948 } else if (intent != null && listener != null) {
949 throw new IllegalArgumentException("cannot register both listener and intent");
950 } else if (intent != null) {
951 checkPendingIntent(intent);
952 return getReceiver(intent, pid, uid, packageName);
953 } else {
954 return getReceiver(listener, pid, uid, packageName);
955 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700956 }
957
Nick Pellye0fd6932012-07-11 10:26:13 -0700958 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700959 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
960 PendingIntent intent, String packageName) {
961 if (request == null) request = DEFAULT_LOCATION_REQUEST;
962 checkPackageName(packageName);
963 checkPermissionAndRequest(request);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700965 final int pid = Binder.getCallingPid();
966 final int uid = Binder.getCallingUid();
967 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968
Nick Pelly2b7a0d02012-08-17 15:09:44 -0700969 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 long identity = Binder.clearCallingIdentity();
971 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700972 synchronized (mLock) {
973 requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400974 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 } finally {
976 Binder.restoreCallingIdentity(identity);
977 }
978 }
979
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700980 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
981 int pid, int uid, String packageName) {
982 // Figure out the provider. Either its explicitly request (legacy use cases), or
983 // use the fused provider
984 if (request == null) request = DEFAULT_LOCATION_REQUEST;
985 String name = request.getProvider();
986 if (name == null) name = LocationManager.FUSED_PROVIDER;
987 LocationProviderInterface provider = mProvidersByName.get(name);
988 if (provider == null) {
989 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
990 }
991
992 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
993 name + " " + request + " from " + packageName + "(" + uid + ")");
994
995 UpdateRecord record = new UpdateRecord(name, request, receiver);
996 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
997 if (oldRecord != null) {
998 oldRecord.disposeLocked(false);
999 }
1000
1001 boolean isProviderEnabled = isAllowedBySettingsLocked(name);
1002 if (isProviderEnabled) {
1003 applyRequirementsLocked(name);
1004 } else {
1005 // Notify the listener that updates are currently disabled
1006 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
1008 }
1009
Nick Pellye0fd6932012-07-11 10:26:13 -07001010 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001011 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1012 String packageName) {
1013 checkPackageName(packageName);
1014 checkPermission();
1015 final int pid = Binder.getCallingPid();
1016 final int uid = Binder.getCallingUid();
1017 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1018
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001019 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001020 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001022 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001023 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001025 } finally {
1026 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 }
1028 }
1029
1030 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001031 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1032
1033 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1034 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1035 synchronized (receiver) {
1036 if (receiver.mPendingBroadcasts > 0) {
1037 decrementPendingBroadcasts();
1038 receiver.mPendingBroadcasts = 0;
1039 }
1040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 }
1042
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001043 // Record which providers were associated with this listener
1044 HashSet<String> providers = new HashSet<String>();
1045 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1046 if (oldRecords != null) {
1047 // Call dispose() on the obsolete update records.
1048 for (UpdateRecord record : oldRecords.values()) {
1049 record.disposeLocked(false);
1050 }
1051 // Accumulate providers
1052 providers.addAll(oldRecords.keySet());
1053 }
1054
1055 // update provider
1056 for (String provider : providers) {
1057 // If provider is already disabled, don't need to do anything
1058 if (!isAllowedBySettingsLocked(provider)) {
1059 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 }
1061
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001062 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 }
1064 }
1065
Nick Pellye0fd6932012-07-11 10:26:13 -07001066 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001067 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001068 if (D) Log.d(TAG, "getLastLocation: " + request);
1069 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1070 String perm = checkPermissionAndRequest(request);
Nick Pelly4035f5a2012-08-17 14:43:49 -07001071 checkPackageName(packageName);
1072
1073 if (mBlacklist.isBlacklisted(packageName)) {
1074 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1075 packageName);
1076 return null;
1077 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001078
1079 synchronized (mLock) {
1080 // Figure out the provider. Either its explicitly request (deprecated API's),
1081 // or use the fused provider
1082 String name = request.getProvider();
1083 if (name == null) name = LocationManager.FUSED_PROVIDER;
1084 LocationProviderInterface provider = mProvidersByName.get(name);
1085 if (provider == null) return null;
1086
1087 if (!isAllowedBySettingsLocked(name)) return null;
1088
1089 Location location = mLastLocation.get(name);
1090 if (ACCESS_FINE_LOCATION.equals(perm)) {
1091 return location;
1092 } else {
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001093 return mLocationFudger.getOrCreate(location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001094 }
1095 }
1096 }
1097
1098 @Override
1099 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1100 String packageName) {
1101 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1102 checkPermissionAndRequest(request);
1103 checkPendingIntent(intent);
1104 checkPackageName(packageName);
1105
1106 if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
1107
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001108 // geo-fence manager uses the public location API, need to clear identity
1109 int uid = Binder.getCallingUid();
1110 long identity = Binder.clearCallingIdentity();
1111 try {
1112 mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
1113 } finally {
1114 Binder.restoreCallingIdentity(identity);
1115 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001116 }
1117
1118 @Override
1119 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
1120 checkPermission();
1121 checkPendingIntent(intent);
1122 checkPackageName(packageName);
1123
1124 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1125
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001126 // geo-fence manager uses the public location API, need to clear identity
1127 long identity = Binder.clearCallingIdentity();
1128 try {
1129 mGeofenceManager.removeFence(geofence, intent);
1130 } finally {
1131 Binder.restoreCallingIdentity(identity);
1132 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001133 }
1134
1135
1136 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001138 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 return false;
1140 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001141 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 PackageManager.PERMISSION_GRANTED) {
1143 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1144 }
1145
1146 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001147 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001149 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 return false;
1151 }
1152 return true;
1153 }
1154
Nick Pellye0fd6932012-07-11 10:26:13 -07001155 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001157 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001158 try {
1159 mGpsStatusProvider.removeGpsStatusListener(listener);
1160 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001161 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 }
1164 }
1165
Nick Pellye0fd6932012-07-11 10:26:13 -07001166 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001168 if (provider == null) {
1169 // throw NullPointerException to remain compatible with previous implementation
1170 throw new NullPointerException();
1171 }
1172
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001173 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001175 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 != PackageManager.PERMISSION_GRANTED)) {
1177 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1178 }
1179
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001180 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001181 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001182 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001183
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001184 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 }
1186 }
1187
Nick Pellye0fd6932012-07-11 10:26:13 -07001188 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001189 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001190 if (Binder.getCallingUid() != Process.myUid()) {
1191 throw new SecurityException(
1192 "calling sendNiResponse from outside of the system is not allowed");
1193 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001194 try {
1195 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001196 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001197 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001198 return false;
1199 }
1200 }
1201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001203 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001204 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001205 * accessed by the caller
1206 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001207 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001208 public ProviderProperties getProviderProperties(String provider) {
1209 checkPermission();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001211 LocationProviderInterface p;
1212 synchronized (mLock) {
1213 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 }
1215
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001216 if (p == null) return null;
1217 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 }
1219
Nick Pellye0fd6932012-07-11 10:26:13 -07001220 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 public boolean isProviderEnabled(String provider) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001222 checkPermission();
1223 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1224
1225 synchronized (mLock) {
1226 LocationProviderInterface p = mProvidersByName.get(provider);
1227 if (p == null) return false;
1228
1229 return isAllowedBySettingsLocked(provider);
1230 }
1231 }
1232
1233 private void checkCallerIsProvider() {
1234 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1235 == PackageManager.PERMISSION_GRANTED) {
1236 return;
1237 }
1238
1239 // Previously we only used the INSTALL_LOCATION_PROVIDER
1240 // check. But that is system or signature
1241 // protection level which is not flexible enough for
1242 // providers installed oustide the system image. So
1243 // also allow providers with a UID matching the
1244 // currently bound package name
1245
1246 int uid = Binder.getCallingUid();
1247
1248 if (mGeocodeProvider != null) {
1249 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1250 }
1251 for (LocationProviderProxy proxy : mProxyProviders) {
1252 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1253 }
1254 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1255 "or UID of a currently bound location provider");
1256 }
1257
1258 private boolean doesPackageHaveUid(int uid, String packageName) {
1259 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 return false;
1261 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001262 try {
1263 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1264 if (appInfo.uid != uid) {
1265 return false;
1266 }
1267 } catch (NameNotFoundException e) {
1268 return false;
1269 }
1270 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 }
1272
Nick Pellye0fd6932012-07-11 10:26:13 -07001273 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001274 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001275 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001276
Nick Pelly2eeeec22012-07-18 13:13:37 -07001277 if (!location.isComplete()) {
1278 Log.w(TAG, "Dropping incomplete location: " + location);
1279 return;
1280 }
1281
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001282 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1283 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001284 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001285 mLocationHandler.sendMessageAtFrontOfQueue(m);
1286 }
1287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288
1289 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1290 // Always broadcast the first update
1291 if (lastLoc == null) {
1292 return true;
1293 }
1294
Nick Pellyf1be6862012-05-15 10:53:42 -07001295 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001296 long minTime = record.mRequest.getFastestInterval();
Nick Pelly2eeeec22012-07-18 13:13:37 -07001297 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001298 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 return false;
1300 }
1301
1302 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001303 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 if (minDistance > 0.0) {
1305 if (loc.distanceTo(lastLoc) <= minDistance) {
1306 return false;
1307 }
1308 }
1309
1310 return true;
1311 }
1312
Mike Lockwooda4903f22010-02-17 06:42:23 -05001313 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001314 if (D) Log.d(TAG, "incoming location: " + location);
1315
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001316 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001317 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001319 if (records == null || records.size() == 0) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001321 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001322 if (p == null) return;
1323
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001324 // Add the coarse location as an extra
1325 Location coarse = mLocationFudger.getOrCreate(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001326
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001327 // Update last known locations
1328 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001329 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001330 lastLocation = new Location(provider);
1331 mLastLocation.put(provider, lastLocation);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001332 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001333 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 // Fetch latest status update time
1336 long newStatusUpdateTime = p.getStatusUpdateTime();
1337
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001338 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 Bundle extras = new Bundle();
1340 int status = p.getStatus(extras);
1341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001343 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001346 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001348 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001349
1350 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1351 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1352 receiver.mPackageName);
1353 continue;
1354 }
1355
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001356 if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
1357 location = lastLocation; // use fine location
1358 } else {
1359 location = coarse; // use coarse location
1360 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001362 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001363 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1364 if (lastLoc == null) {
1365 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001366 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001367 } else {
1368 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001370 if (!receiver.callLocationChangedLocked(location)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001371 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001372 receiverDead = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 }
1374 }
1375
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001376 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1378 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1379
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001380 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001382 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001383 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001384 }
1385 }
1386
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001387 // track expired records
1388 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1389 if (deadUpdateRecords == null) {
1390 deadUpdateRecords = new ArrayList<UpdateRecord>();
1391 }
1392 deadUpdateRecords.add(r);
1393 }
1394 // track dead receivers
1395 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001396 if (deadReceivers == null) {
1397 deadReceivers = new ArrayList<Receiver>();
1398 }
1399 if (!deadReceivers.contains(receiver)) {
1400 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 }
1402 }
1403 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001404
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001405 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001407 for (Receiver receiver : deadReceivers) {
1408 removeUpdatesLocked(receiver);
1409 }
1410 }
1411 if (deadUpdateRecords != null) {
1412 for (UpdateRecord r : deadUpdateRecords) {
1413 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 }
1415 }
1416 }
1417
1418 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 @Override
1420 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001421 switch (msg.what) {
1422 case MSG_LOCATION_CHANGED:
1423 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1424 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 }
1426 }
1427 }
1428
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001429 private void handleLocationChanged(Location location, boolean passive) {
1430 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001431
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001432 if (!passive) {
1433 // notify passive provider of the new location
1434 mPassiveProvider.updateLocation(location);
1435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001437 synchronized (mLock) {
1438 if (isAllowedBySettingsLocked(provider)) {
1439 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443
Mike Lockwoode97ae402010-09-29 15:23:46 -04001444 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1445 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001446 public void onPackageDisappeared(String packageName, int reason) {
1447 // remove all receivers associated with this package name
1448 synchronized (mLock) {
1449 ArrayList<Receiver> deadReceivers = null;
1450
1451 for (Receiver receiver : mReceivers.values()) {
1452 if (receiver.mPackageName.equals(packageName)) {
1453 if (deadReceivers == null) {
1454 deadReceivers = new ArrayList<Receiver>();
1455 }
1456 deadReceivers.add(receiver);
1457 }
1458 }
1459
1460 // perform removal outside of mReceivers loop
1461 if (deadReceivers != null) {
1462 for (Receiver receiver : deadReceivers) {
1463 removeUpdatesLocked(receiver);
1464 }
1465 }
1466 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001467 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001468 };
1469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 // Wake locks
1471
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001472 private void incrementPendingBroadcasts() {
1473 synchronized (mWakeLock) {
1474 if (mPendingBroadcasts++ == 0) {
1475 try {
1476 mWakeLock.acquire();
1477 log("Acquired wakelock");
1478 } catch (Exception e) {
1479 // This is to catch a runtime exception thrown when we try to release an
1480 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001481 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001482 }
1483 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001484 }
1485 }
1486
1487 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001488 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001489 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001490 try {
1491 // Release wake lock
1492 if (mWakeLock.isHeld()) {
1493 mWakeLock.release();
1494 log("Released wakelock");
1495 } else {
1496 log("Can't release wakelock again!");
1497 }
1498 } catch (Exception e) {
1499 // This is to catch a runtime exception thrown when we try to release an
1500 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001501 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001502 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001503 }
1504 }
1505 }
1506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 // Geocoder
1508
Nick Pellye0fd6932012-07-11 10:26:13 -07001509 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001510 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001511 return mGeocodeProvider != null;
1512 }
1513
Nick Pellye0fd6932012-07-11 10:26:13 -07001514 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001516 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001517 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001518 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1519 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001521 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 }
1523
Mike Lockwooda55c3212009-04-15 11:10:11 -04001524
Nick Pellye0fd6932012-07-11 10:26:13 -07001525 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001527 double lowerLeftLatitude, double lowerLeftLongitude,
1528 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001529 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001530
1531 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001532 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1533 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1534 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001536 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 }
1538
1539 // Mock Providers
1540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 private void checkMockPermissionsSafe() {
1542 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1543 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1544 if (!allowMocks) {
1545 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1546 }
1547
1548 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1549 PackageManager.PERMISSION_GRANTED) {
1550 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001551 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 }
1553
Nick Pellye0fd6932012-07-11 10:26:13 -07001554 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001555 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 checkMockPermissionsSafe();
1557
Mike Lockwooda4903f22010-02-17 06:42:23 -05001558 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1559 throw new IllegalArgumentException("Cannot mock the passive location provider");
1560 }
1561
Mike Lockwood86328a92009-10-23 08:38:25 -04001562 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001563 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001564 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001565 // remove the real provider if we are replacing GPS or network provider
1566 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001567 || LocationManager.NETWORK_PROVIDER.equals(name)
1568 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001569 LocationProviderInterface p = mProvidersByName.get(name);
1570 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001571 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001572 }
1573 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001574 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1576 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001577 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001578 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001579 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 updateProvidersLocked();
1581 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001582 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 }
1584
Nick Pellye0fd6932012-07-11 10:26:13 -07001585 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 public void removeTestProvider(String provider) {
1587 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001588 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001589 MockProvider mockProvider = mMockProviders.get(provider);
1590 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1592 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001593 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001594 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001595 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001596
1597 // reinstate real provider if available
1598 LocationProviderInterface realProvider = mRealProviders.get(provider);
1599 if (realProvider != null) {
1600 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001601 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001602 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001604 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 }
1606 }
1607
Nick Pellye0fd6932012-07-11 10:26:13 -07001608 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 public void setTestProviderLocation(String provider, Location loc) {
1610 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001611 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001612 MockProvider mockProvider = mMockProviders.get(provider);
1613 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1615 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001616 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1617 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001618 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001619 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620 }
1621 }
1622
Nick Pellye0fd6932012-07-11 10:26:13 -07001623 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 public void clearTestProviderLocation(String provider) {
1625 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001626 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001627 MockProvider mockProvider = mMockProviders.get(provider);
1628 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1630 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001631 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 }
1633 }
1634
Nick Pellye0fd6932012-07-11 10:26:13 -07001635 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 public void setTestProviderEnabled(String provider, boolean enabled) {
1637 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001638 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001639 MockProvider mockProvider = mMockProviders.get(provider);
1640 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1642 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001643 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001645 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 mEnabledProviders.add(provider);
1647 mDisabledProviders.remove(provider);
1648 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001649 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650 mEnabledProviders.remove(provider);
1651 mDisabledProviders.add(provider);
1652 }
1653 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001654 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 }
1656 }
1657
Nick Pellye0fd6932012-07-11 10:26:13 -07001658 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 public void clearTestProviderEnabled(String provider) {
1660 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001661 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001662 MockProvider mockProvider = mMockProviders.get(provider);
1663 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1665 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001666 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 mEnabledProviders.remove(provider);
1668 mDisabledProviders.remove(provider);
1669 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001670 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
1672 }
1673
Nick Pellye0fd6932012-07-11 10:26:13 -07001674 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1676 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001677 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001678 MockProvider mockProvider = mMockProviders.get(provider);
1679 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1681 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001682 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 }
1684 }
1685
Nick Pellye0fd6932012-07-11 10:26:13 -07001686 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 public void clearTestProviderStatus(String provider) {
1688 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001689 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001690 MockProvider mockProvider = mMockProviders.get(provider);
1691 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1693 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001694 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 }
1696 }
1697
1698 private void log(String log) {
1699 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001700 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 }
1702 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001703
1704 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1706 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1707 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001708 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 + Binder.getCallingPid()
1710 + ", uid=" + Binder.getCallingUid());
1711 return;
1712 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001713
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001714 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001717 for (Receiver receiver : mReceivers.values()) {
1718 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001721 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1722 pw.println(" " + entry.getKey() + ":");
1723 for (UpdateRecord record : entry.getValue()) {
1724 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 }
1726 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001728 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1729 String provider = entry.getKey();
1730 Location location = entry.getValue();
1731 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001733
Nick Pellye0fd6932012-07-11 10:26:13 -07001734 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 if (mEnabledProviders.size() > 0) {
1737 pw.println(" Enabled Providers:");
1738 for (String i : mEnabledProviders) {
1739 pw.println(" " + i);
1740 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 }
1743 if (mDisabledProviders.size() > 0) {
1744 pw.println(" Disabled Providers:");
1745 for (String i : mDisabledProviders) {
1746 pw.println(" " + i);
1747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001749 pw.append(" ");
1750 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 if (mMockProviders.size() > 0) {
1752 pw.println(" Mock Providers:");
1753 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001754 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 }
1756 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001757
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001758 pw.append(" fudger: ");
1759 mLocationFudger.dump(fd, pw, args);
1760
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001761 if (args.length > 0 && "short".equals(args[0])) {
1762 return;
1763 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001764 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001765 pw.print(provider.getName() + " Internal State");
1766 if (provider instanceof LocationProviderProxy) {
1767 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1768 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001769 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001770 pw.println(":");
1771 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 }
1774 }
1775}