blob: cae060a8493e0cfe5fc2c7e4e1edb1b1cc38d19f [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
Svet Ganovadc1cf42015-06-15 16:36:24 -070019import android.content.pm.PackageManagerInternal;
destradaaea8a8a62014-06-23 18:19:03 -070020import com.android.internal.content.PackageMonitor;
21import com.android.internal.location.ProviderProperties;
22import com.android.internal.location.ProviderRequest;
23import com.android.internal.os.BackgroundThread;
destradaaa4fa3b52014-07-09 10:46:39 -070024import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070025import com.android.server.location.FlpHardwareProvider;
26import com.android.server.location.FusedProxy;
27import com.android.server.location.GeocoderProxy;
28import com.android.server.location.GeofenceManager;
29import com.android.server.location.GeofenceProxy;
30import com.android.server.location.GpsLocationProvider;
31import com.android.server.location.GpsMeasurementsProvider;
destradaa4b3e3932014-07-21 18:01:47 -070032import com.android.server.location.GpsNavigationMessageProvider;
destradaaea8a8a62014-06-23 18:19:03 -070033import com.android.server.location.LocationBlacklist;
34import com.android.server.location.LocationFudger;
35import com.android.server.location.LocationProviderInterface;
36import com.android.server.location.LocationProviderProxy;
37import com.android.server.location.LocationRequestStatistics;
38import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
39import com.android.server.location.LocationRequestStatistics.PackageStatistics;
40import com.android.server.location.MockProvider;
41import com.android.server.location.PassiveProvider;
42
Dianne Hackborna06de0f2012-12-11 16:34:47 -080043import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070045import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ContentResolver;
47import android.content.Context;
48import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070049import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070050import android.content.pm.ApplicationInfo;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050051import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070053import android.content.pm.PackageManager.NameNotFoundException;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050054import android.content.pm.ResolveInfo;
55import android.content.pm.Signature;
Amith Yamasanib27528d2014-06-05 15:02:10 -070056import android.content.pm.UserInfo;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050057import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070058import android.database.ContentObserver;
destradaaa4fa3b52014-07-09 10:46:39 -070059import android.hardware.location.ActivityRecognitionHardware;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070061import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050062import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070063import android.location.Geofence;
Wei Liu5241a4c2015-05-11 14:00:36 -070064import android.location.IGpsGeofenceHardware;
destradaaea8a8a62014-06-23 18:19:03 -070065import android.location.IGpsMeasurementsListener;
destradaa4b3e3932014-07-21 18:01:47 -070066import android.location.IGpsNavigationMessageListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040068import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.location.ILocationListener;
70import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040071import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.location.Location;
73import android.location.LocationManager;
74import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070075import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import android.os.Binder;
77import android.os.Bundle;
78import android.os.Handler;
79import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070080import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.Message;
82import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070083import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070085import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070086import android.os.UserHandle;
Amith Yamasanib27528d2014-06-05 15:02:10 -070087import android.os.UserManager;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070088import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080091import android.util.Slog;
Amith Yamasanib27528d2014-06-05 15:02:10 -070092
Mike Lockwood43e33f22010-03-26 10:41:48 -040093import java.io.FileDescriptor;
94import java.io.PrintWriter;
95import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070096import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040097import java.util.HashMap;
98import java.util.HashSet;
99import java.util.List;
100import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400101import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102
103/**
104 * The service class that manages LocationProviders and issues location
105 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800107public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800109 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700110
111 private static final String WAKELOCK_KEY = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
Victoria Lease37425c32012-10-16 16:08:48 -0700113 // Location resolution level: no location data whatsoever
114 private static final int RESOLUTION_LEVEL_NONE = 0;
115 // Location resolution level: coarse location data only
116 private static final int RESOLUTION_LEVEL_COARSE = 1;
117 // Location resolution level: fine location data
118 private static final int RESOLUTION_LEVEL_FINE = 2;
119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700121 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700123 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400124 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700125 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
126
127 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700128 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700129 private static final String FUSED_LOCATION_SERVICE_ACTION =
130 "com.android.location.service.FusedLocationProvider";
131
132 private static final int MSG_LOCATION_CHANGED = 1;
133
David Christie1b9b7b12013-04-15 15:31:11 -0700134 private static final long NANOS_PER_MILLI = 1000000L;
135
David Christie0b837452013-07-29 16:02:13 -0700136 // The maximum interval a location request can have and still be considered "high power".
137 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
138
Nick Pellyf1be6862012-05-15 10:53:42 -0700139 // Location Providers may sometimes deliver location updates
140 // slightly faster that requested - provide grace period so
141 // we don't unnecessarily filter events that are otherwise on
142 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700143 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700144
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700145 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
146
147 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800148 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700149
150 // used internally for synchronization
151 private final Object mLock = new Object();
152
Victoria Lease5cd731a2012-12-19 15:04:21 -0800153 // --- fields below are final after systemReady() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700154 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700155 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700156 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700157 private PowerManager mPowerManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700158 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700159 private GeocoderProxy mGeocodeProvider;
160 private IGpsStatusProvider mGpsStatusProvider;
161 private INetInitiatedListener mNetInitiatedListener;
162 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700163 private PassiveProvider mPassiveProvider; // track passive provider for special cases
164 private LocationBlacklist mBlacklist;
destradaaea8a8a62014-06-23 18:19:03 -0700165 private GpsMeasurementsProvider mGpsMeasurementsProvider;
destradaa4b3e3932014-07-21 18:01:47 -0700166 private GpsNavigationMessageProvider mGpsNavigationMessageProvider;
Wei Liu5241a4c2015-05-11 14:00:36 -0700167 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 // Set of providers that are explicitly enabled
171 private final Set<String> mEnabledProviders = new HashSet<String>();
172
173 // Set of providers that are explicitly disabled
174 private final Set<String> mDisabledProviders = new HashSet<String>();
175
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700176 // Mock (test) providers
177 private final HashMap<String, MockProvider> mMockProviders =
178 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700180 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400181 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500184 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400186
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700187 // real providers, saved here when mocked out
188 private final HashMap<String, LocationProviderInterface> mRealProviders =
189 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700191 // mapping from provider name to provider
192 private final HashMap<String, LocationProviderInterface> mProvidersByName =
193 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700195 // mapping from provider name to all its UpdateRecords
196 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
197 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700198
David Christie2ff96af2014-01-30 16:09:37 -0800199 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
200
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700201 // mapping from provider name to last known location
202 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
David Christie1b9b7b12013-04-15 15:31:11 -0700204 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
205 // locations stored here are not fudged for coarse permissions.
206 private final HashMap<String, Location> mLastLocationCoarseInterval =
207 new HashMap<String, Location>();
208
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700209 // all providers that operate over proxy, for authorizing incoming location
210 private final ArrayList<LocationProviderProxy> mProxyProviders =
211 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212
Victoria Lease38389b62012-09-30 11:44:22 -0700213 // current active user on the device - other users are denied location data
214 private int mCurrentUserId = UserHandle.USER_OWNER;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700215 private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER };
Victoria Lease38389b62012-09-30 11:44:22 -0700216
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700217 public LocationManagerService(Context context) {
218 super();
219 mContext = context;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800220 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800221
Svet Ganovadc1cf42015-06-15 16:36:24 -0700222 // Let the package manager query which are the default location
223 // providers as they get certain permissions granted by default.
224 PackageManagerInternal packageManagerInternal = LocalServices.getService(
225 PackageManagerInternal.class);
226 packageManagerInternal.setLocationPackagesProvider(
227 new PackageManagerInternal.PackagesProvider() {
228 @Override
229 public String[] getPackages(int userId) {
230 return mContext.getResources().getStringArray(
231 com.android.internal.R.array.config_locationProviderPackageNames);
232 }
233 });
234
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700235 if (D) Log.d(TAG, "Constructed");
236
237 // most startup is deferred until systemReady()
238 }
239
Svetoslav Ganova0027152013-06-25 14:59:53 -0700240 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700241 synchronized (mLock) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800242 if (D) Log.d(TAG, "systemReady()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700243
Victoria Lease5cd731a2012-12-19 15:04:21 -0800244 // fetch package manager
245 mPackageManager = mContext.getPackageManager();
246
Victoria Lease0aa28602013-05-29 15:28:26 -0700247 // fetch power manager
248 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800249
250 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700251 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800252
253 // prepare mLocationHandler's dependents
254 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
255 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
256 mBlacklist.init();
257 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
258
Dianne Hackbornc2293022013-02-06 23:14:49 -0800259 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700260 AppOpsManager.OnOpChangedListener callback
261 = new AppOpsManager.OnOpChangedInternalListener() {
262 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800263 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700264 for (Receiver receiver : mReceivers.values()) {
265 receiver.updateMonitoring(true);
266 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800267 applyAllProviderRequirementsLocked();
268 }
269 }
270 };
271 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
272
David Christieb870dbf2015-06-22 12:42:53 -0700273 PackageManager.OnPermissionsChangedListener permissionListener
274 = new PackageManager.OnPermissionsChangedListener() {
275 @Override
276 public void onPermissionsChanged(final int uid) {
277 synchronized (mLock) {
278 applyAllProviderRequirementsLocked();
279 }
280 }
281 };
282 mPackageManager.addOnPermissionsChangeListener(permissionListener);
283
Amith Yamasanib27528d2014-06-05 15:02:10 -0700284 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
285 updateUserProfiles(mCurrentUserId);
286
Victoria Lease5cd731a2012-12-19 15:04:21 -0800287 // prepare providers
288 loadProvidersLocked();
289 updateProvidersLocked();
290 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700291
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700292 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700293 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700294 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700295 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800296 @Override
297 public void onChange(boolean selfChange) {
298 synchronized (mLock) {
299 updateProvidersLocked();
300 }
301 }
302 }, UserHandle.USER_ALL);
303 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700304
Victoria Lease38389b62012-09-30 11:44:22 -0700305 // listen for user change
306 IntentFilter intentFilter = new IntentFilter();
307 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700308 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
309 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700310
311 mContext.registerReceiverAsUser(new BroadcastReceiver() {
312 @Override
313 public void onReceive(Context context, Intent intent) {
314 String action = intent.getAction();
315 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
316 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700317 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
318 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
319 updateUserProfiles(mCurrentUserId);
Victoria Lease38389b62012-09-30 11:44:22 -0700320 }
321 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800322 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700323 }
324
Amith Yamasanib27528d2014-06-05 15:02:10 -0700325 /**
326 * Makes a list of userids that are related to the current user. This is
327 * relevant when using managed profiles. Otherwise the list only contains
328 * the current user.
329 *
330 * @param currentUserId the current user, who might have an alter-ego.
331 */
332 void updateUserProfiles(int currentUserId) {
333 List<UserInfo> profiles = mUserManager.getProfiles(currentUserId);
334 synchronized (mLock) {
335 mCurrentUserProfiles = new int[profiles.size()];
336 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
337 mCurrentUserProfiles[i] = profiles.get(i).id;
338 }
339 }
340 }
341
342 /**
343 * Checks if the specified userId matches any of the current foreground
344 * users stored in mCurrentUserProfiles.
345 */
346 private boolean isCurrentProfile(int userId) {
347 synchronized (mLock) {
348 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
349 if (mCurrentUserProfiles[i] == userId) {
350 return true;
351 }
352 }
353 return false;
354 }
355 }
356
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500357 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
358 PackageManager pm = mContext.getPackageManager();
359 String systemPackageName = mContext.getPackageName();
360 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
361
362 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
363 new Intent(FUSED_LOCATION_SERVICE_ACTION),
364 PackageManager.GET_META_DATA, mCurrentUserId);
365 for (ResolveInfo rInfo : rInfos) {
366 String packageName = rInfo.serviceInfo.packageName;
367
368 // Check that the signature is in the list of supported sigs. If it's not in
369 // this list the standard provider binding logic won't bind to it.
370 try {
371 PackageInfo pInfo;
372 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
373 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
374 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
375 ", but has wrong signature, ignoring");
376 continue;
377 }
378 } catch (NameNotFoundException e) {
379 Log.e(TAG, "missing package: " + packageName);
380 continue;
381 }
382
383 // Get the version info
384 if (rInfo.serviceInfo.metaData == null) {
385 Log.w(TAG, "Found fused provider without metadata: " + packageName);
386 continue;
387 }
388
389 int version = rInfo.serviceInfo.metaData.getInt(
390 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
391 if (version == 0) {
392 // This should be the fallback fused location provider.
393
394 // Make sure it's in the system partition.
395 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
396 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
397 continue;
398 }
399
400 // Check that the fallback is signed the same as the OS
401 // as a proxy for coreApp="true"
402 if (pm.checkSignatures(systemPackageName, packageName)
403 != PackageManager.SIGNATURE_MATCH) {
404 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
405 + packageName);
406 continue;
407 }
408
409 // Found a valid fallback.
410 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
411 return;
412 } else {
413 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
414 }
415 }
416
417 throw new IllegalStateException("Unable to find a fused location provider that is in the "
418 + "system partition with version 0 and signed with the platform certificate. "
419 + "Such a package is needed to provide a default fused location provider in the "
420 + "event that no other fused location provider has been installed or is currently "
421 + "available. For example, coreOnly boot mode when decrypting the data "
422 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
423 }
424
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700425 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700426 // create a passive location provider, which is always enabled
427 PassiveProvider passiveProvider = new PassiveProvider(this);
428 addProviderLocked(passiveProvider);
429 mEnabledProviders.add(passiveProvider.getName());
430 mPassiveProvider = passiveProvider;
431
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700432 if (GpsLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700433 // Create a gps location provider
434 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
435 mLocationHandler.getLooper());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700436 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
437 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
438 addProviderLocked(gpsProvider);
439 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
Wei Liu5241a4c2015-05-11 14:00:36 -0700440 mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
441 mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
442 mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700443 }
444
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700445 /*
446 Load package name(s) containing location provider support.
447 These packages can contain services implementing location providers:
448 Geocoder Provider, Network Location Provider, and
449 Fused Location Provider. They will each be searched for
450 service components implementing these providers.
451 The location framework also has support for installation
452 of new location providers at run-time. The new package does not
453 have to be explicitly listed here, however it must have a signature
454 that matches the signature of at least one package on this list.
455 */
456 Resources resources = mContext.getResources();
457 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500458 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700459 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500460 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
461 Arrays.toString(pkgs));
462 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
463
464 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700465
466 // bind to network provider
467 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
468 mContext,
469 LocationManager.NETWORK_PROVIDER,
470 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700471 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
472 com.android.internal.R.string.config_networkLocationProviderPackageName,
473 com.android.internal.R.array.config_locationProviderPackageNames,
474 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700475 if (networkProvider != null) {
476 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
477 mProxyProviders.add(networkProvider);
478 addProviderLocked(networkProvider);
479 } else {
480 Slog.w(TAG, "no network location provider found");
481 }
482
483 // bind to fused provider
484 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
485 mContext,
486 LocationManager.FUSED_PROVIDER,
487 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700488 com.android.internal.R.bool.config_enableFusedLocationOverlay,
489 com.android.internal.R.string.config_fusedLocationProviderPackageName,
490 com.android.internal.R.array.config_locationProviderPackageNames,
491 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700492 if (fusedLocationProvider != null) {
493 addProviderLocked(fusedLocationProvider);
494 mProxyProviders.add(fusedLocationProvider);
495 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700496 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700497 } else {
498 Slog.e(TAG, "no fused location provider found",
499 new IllegalStateException("Location service needs a fused location provider"));
500 }
501
502 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700503 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
504 com.android.internal.R.bool.config_enableGeocoderOverlay,
505 com.android.internal.R.string.config_geocoderProviderPackageName,
506 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800507 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700508 if (mGeocodeProvider == null) {
509 Slog.e(TAG, "no geocoder provider found");
510 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700511
destradaaa4fa3b52014-07-09 10:46:39 -0700512 // bind to fused hardware provider if supported
destradaabeea4422014-07-30 18:17:21 -0700513 // in devices without support, requesting an instance of FlpHardwareProvider will raise an
514 // exception, so make sure we only do that when supported
515 FlpHardwareProvider flpHardwareProvider;
destradaa5ce66d82014-05-28 18:24:08 -0700516 if (FlpHardwareProvider.isSupported()) {
destradaabeea4422014-07-30 18:17:21 -0700517 flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
destradaaf9a274c2014-07-25 15:11:56 -0700518 FusedProxy fusedProxy = FusedProxy.createAndBind(
519 mContext,
520 mLocationHandler,
521 flpHardwareProvider.getLocationHardware(),
522 com.android.internal.R.bool.config_enableHardwareFlpOverlay,
523 com.android.internal.R.string.config_hardwareFlpPackageName,
524 com.android.internal.R.array.config_locationProviderPackageNames);
525 if (fusedProxy == null) {
526 Slog.e(TAG, "Unable to bind FusedProxy.");
527 }
destradaacfbdcd22014-04-30 11:29:11 -0700528 } else {
destradaabeea4422014-07-30 18:17:21 -0700529 flpHardwareProvider = null;
destradaaf9a274c2014-07-25 15:11:56 -0700530 Slog.e(TAG, "FLP HAL not supported");
531 }
532
533 // bind to geofence provider
534 GeofenceProxy provider = GeofenceProxy.createAndBind(
535 mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
536 com.android.internal.R.string.config_geofenceProviderPackageName,
537 com.android.internal.R.array.config_locationProviderPackageNames,
538 mLocationHandler,
Wei Liu5241a4c2015-05-11 14:00:36 -0700539 mGpsGeofenceProxy,
destradaabeea4422014-07-30 18:17:21 -0700540 flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
destradaaf9a274c2014-07-25 15:11:56 -0700541 if (provider == null) {
542 Slog.e(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700543 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900544
destradaaa4fa3b52014-07-09 10:46:39 -0700545 // bind to the hardware activity recognition if supported
546 if (ActivityRecognitionHardware.isSupported()) {
547 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
548 mContext,
549 mLocationHandler,
550 ActivityRecognitionHardware.getInstance(mContext),
551 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
552 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
553 com.android.internal.R.array.config_locationProviderPackageNames);
554
555 if (proxy == null) {
556 Slog.e(TAG, "Unable to bind ActivityRecognitionProxy.");
557 }
558 } else {
559 Slog.e(TAG, "Hardware Activity-Recognition not supported.");
560 }
561
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900562 String[] testProviderStrings = resources.getStringArray(
563 com.android.internal.R.array.config_testLocationProviders);
564 for (String testProviderString : testProviderStrings) {
565 String fragments[] = testProviderString.split(",");
566 String name = fragments[0].trim();
567 if (mProvidersByName.get(name) != null) {
568 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
569 }
570 ProviderProperties properties = new ProviderProperties(
571 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
572 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
573 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
574 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
575 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
576 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
577 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
578 Integer.parseInt(fragments[8]) /* powerRequirement */,
579 Integer.parseInt(fragments[9]) /* accuracy */);
580 addTestProviderLocked(name, properties);
581 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700582 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700585 * Called when the device's active user changes.
586 * @param userId the new active user's UserId
587 */
588 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800589 if (mCurrentUserId == userId) {
590 return;
591 }
Victoria Lease83762d22012-10-03 13:51:17 -0700592 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800593 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700594 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700595 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700596 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700597 for (LocationProviderInterface p : mProviders) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700598 updateProviderListenersLocked(p.getName(), false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700599 }
Victoria Lease38389b62012-09-30 11:44:22 -0700600 mCurrentUserId = userId;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700601 updateUserProfiles(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700602 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700603 }
604 }
605
606 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
608 * location updates.
609 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700610 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700611 final int mUid; // uid of receiver
612 final int mPid; // pid of receiver
613 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700614 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 final ILocationListener mListener;
617 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700618 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700619 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700621
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400622 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700623
David Christie0b837452013-07-29 16:02:13 -0700624 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700625 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700626 // True if app ops has started monitoring this receiver for high power (gps) locations.
627 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700628 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700629 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700631 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700632 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700635 if (listener != null) {
636 mKey = listener.asBinder();
637 } else {
638 mKey = intent;
639 }
Victoria Lease37425c32012-10-16 16:08:48 -0700640 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700641 mUid = uid;
642 mPid = pid;
643 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700644 if (workSource != null && workSource.size() <= 0) {
645 workSource = null;
646 }
647 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700648 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700649
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700650 updateMonitoring(true);
651
Victoria Lease0aa28602013-05-29 15:28:26 -0700652 // construct/configure wakelock
653 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700654 if (workSource == null) {
655 workSource = new WorkSource(mUid, mPackageName);
656 }
657 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 }
659
660 @Override
661 public boolean equals(Object otherObj) {
662 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700663 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 }
665 return false;
666 }
667
668 @Override
669 public int hashCode() {
670 return mKey.hashCode();
671 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 @Override
674 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700675 StringBuilder s = new StringBuilder();
676 s.append("Reciever[");
677 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700679 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700681 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700683 for (String p : mUpdateRecords.keySet()) {
684 s.append(" ").append(mUpdateRecords.get(p).toString());
685 }
686 s.append("]");
687 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 }
689
David Christie15b31912013-08-13 15:54:32 -0700690 /**
691 * Update AppOp monitoring for this receiver.
692 *
693 * @param allow If true receiver is currently active, if false it's been removed.
694 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700695 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700696 if (mHideFromAppOps) {
697 return;
698 }
699
David Christie15b31912013-08-13 15:54:32 -0700700 boolean requestingLocation = false;
701 boolean requestingHighPowerLocation = false;
702 if (allow) {
703 // See if receiver has any enabled update records. Also note if any update records
704 // are high power (has a high power provider with an interval under a threshold).
705 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
706 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
707 requestingLocation = true;
708 LocationProviderInterface locationProvider
David Christie2ff96af2014-01-30 16:09:37 -0800709 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -0700710 ProviderProperties properties = locationProvider != null
711 ? locationProvider.getProperties() : null;
712 if (properties != null
713 && properties.mPowerRequirement == Criteria.POWER_HIGH
714 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
715 requestingHighPowerLocation = true;
716 break;
717 }
718 }
719 }
720 }
721
David Christie0b837452013-07-29 16:02:13 -0700722 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700723 mOpMonitoring = updateMonitoring(
724 requestingLocation,
725 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700726 AppOpsManager.OP_MONITOR_LOCATION);
727
728 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700729 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700730 mOpHighPowerMonitoring = updateMonitoring(
731 requestingHighPowerLocation,
732 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700733 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700734 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700735 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700736 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
737 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
738 }
David Christie0b837452013-07-29 16:02:13 -0700739 }
740
741 /**
742 * Update AppOps monitoring for a single location request and op type.
743 *
744 * @param allowMonitoring True if monitoring is allowed for this request/op.
745 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
746 * @param op AppOps code for the op to update.
747 * @return True if monitoring is on for this request/op after updating.
748 */
749 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
750 int op) {
751 if (!currentlyMonitoring) {
752 if (allowMonitoring) {
753 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
754 == AppOpsManager.MODE_ALLOWED;
755 }
756 } else {
757 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
758 != AppOpsManager.MODE_ALLOWED) {
759 mAppOps.finishOp(op, mUid, mPackageName);
760 return false;
761 }
762 }
763
764 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700765 }
766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 public boolean isListener() {
768 return mListener != null;
769 }
770
771 public boolean isPendingIntent() {
772 return mPendingIntent != null;
773 }
774
775 public ILocationListener getListener() {
776 if (mListener != null) {
777 return mListener;
778 }
779 throw new IllegalStateException("Request for non-existent listener");
780 }
781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
783 if (mListener != null) {
784 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700785 synchronized (this) {
786 // synchronize to ensure incrementPendingBroadcastsLocked()
787 // is called before decrementPendingBroadcasts()
788 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700789 // call this after broadcasting so we do not increment
790 // if we throw an exeption.
791 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 } catch (RemoteException e) {
794 return false;
795 }
796 } else {
797 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800798 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
800 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700801 synchronized (this) {
802 // synchronize to ensure incrementPendingBroadcastsLocked()
803 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700804 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700805 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700806 // call this after broadcasting so we do not increment
807 // if we throw an exeption.
808 incrementPendingBroadcastsLocked();
809 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 } catch (PendingIntent.CanceledException e) {
811 return false;
812 }
813 }
814 return true;
815 }
816
817 public boolean callLocationChangedLocked(Location location) {
818 if (mListener != null) {
819 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700820 synchronized (this) {
821 // synchronize to ensure incrementPendingBroadcastsLocked()
822 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800823 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700824 // call this after broadcasting so we do not increment
825 // if we throw an exeption.
826 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700827 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 } catch (RemoteException e) {
829 return false;
830 }
831 } else {
832 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800833 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700835 synchronized (this) {
836 // synchronize to ensure incrementPendingBroadcastsLocked()
837 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700838 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700839 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700840 // call this after broadcasting so we do not increment
841 // if we throw an exeption.
842 incrementPendingBroadcastsLocked();
843 }
844 } catch (PendingIntent.CanceledException e) {
845 return false;
846 }
847 }
848 return true;
849 }
850
851 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -0700852 // First update AppOp monitoring.
853 // An app may get/lose location access as providers are enabled/disabled.
854 updateMonitoring(true);
855
Mike Lockwood48f17512009-04-23 09:12:08 -0700856 if (mListener != null) {
857 try {
858 synchronized (this) {
859 // synchronize to ensure incrementPendingBroadcastsLocked()
860 // is called before decrementPendingBroadcasts()
861 if (enabled) {
862 mListener.onProviderEnabled(provider);
863 } else {
864 mListener.onProviderDisabled(provider);
865 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700866 // call this after broadcasting so we do not increment
867 // if we throw an exeption.
868 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700869 }
870 } catch (RemoteException e) {
871 return false;
872 }
873 } else {
874 Intent providerIntent = new Intent();
875 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
876 try {
877 synchronized (this) {
878 // synchronize to ensure incrementPendingBroadcastsLocked()
879 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700880 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700881 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700882 // call this after broadcasting so we do not increment
883 // if we throw an exeption.
884 incrementPendingBroadcastsLocked();
885 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 } catch (PendingIntent.CanceledException e) {
887 return false;
888 }
889 }
890 return true;
891 }
892
Nick Pellyf1be6862012-05-15 10:53:42 -0700893 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700895 if (D) Log.d(TAG, "Location listener died");
896
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400897 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 removeUpdatesLocked(this);
899 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700900 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700901 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700902 }
903 }
904
Nick Pellye0fd6932012-07-11 10:26:13 -0700905 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700906 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
907 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400908 synchronized (this) {
909 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700910 }
911 }
912
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400913 // this must be called while synchronized by caller in a synchronized block
914 // containing the sending of the broadcaset
915 private void incrementPendingBroadcastsLocked() {
916 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700917 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400918 }
919 }
920
921 private void decrementPendingBroadcastsLocked() {
922 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700923 if (mWakeLock.isHeld()) {
924 mWakeLock.release();
925 }
926 }
927 }
928
929 public void clearPendingBroadcastsLocked() {
930 if (mPendingBroadcasts > 0) {
931 mPendingBroadcasts = 0;
932 if (mWakeLock.isHeld()) {
933 mWakeLock.release();
934 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700935 }
936 }
937 }
938
Nick Pellye0fd6932012-07-11 10:26:13 -0700939 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700940 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700941 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400942 //the receiver list if it is not found. If it is not found then the
943 //LocationListener was removed when it had a pending broadcast and should
944 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700945 synchronized (mLock) {
946 IBinder binder = listener.asBinder();
947 Receiver receiver = mReceivers.get(binder);
948 if (receiver != null) {
949 synchronized (receiver) {
950 // so wakelock calls will succeed
951 long identity = Binder.clearCallingIdentity();
952 receiver.decrementPendingBroadcastsLocked();
953 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -0800954 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 }
957 }
958
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700959 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400960 mProviders.add(provider);
961 mProvidersByName.put(provider.getName(), provider);
962 }
963
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700964 private void removeProviderLocked(LocationProviderInterface provider) {
965 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400966 mProviders.remove(provider);
967 mProvidersByName.remove(provider.getName());
968 }
969
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800970 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800971 * Returns "true" if access to the specified location provider is allowed by the current
972 * user's settings. Access to all location providers is forbidden to non-location-provider
973 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800974 *
975 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800976 * @return
977 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800978 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 if (mEnabledProviders.contains(provider)) {
980 return true;
981 }
982 if (mDisabledProviders.contains(provider)) {
983 return false;
984 }
985 // Use system settings
986 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987
Victoria Leaseb711d572012-10-02 13:14:11 -0700988 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 }
990
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700991 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800992 * Returns "true" if access to the specified location provider is allowed by the specified
993 * user's settings. Access to all location providers is forbidden to non-location-provider
994 * processes belonging to background users.
995 *
996 * @param provider the name of the location provider
997 * @param uid the requestor's UID
998 * @return
999 */
1000 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001001 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001002 return false;
1003 }
1004 return isAllowedByCurrentUserSettingsLocked(provider);
1005 }
1006
1007 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001008 * Returns the permission string associated with the specified resolution level.
1009 *
1010 * @param resolutionLevel the resolution level
1011 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001012 */
Victoria Lease37425c32012-10-16 16:08:48 -07001013 private String getResolutionPermission(int resolutionLevel) {
1014 switch (resolutionLevel) {
1015 case RESOLUTION_LEVEL_FINE:
1016 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1017 case RESOLUTION_LEVEL_COARSE:
1018 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1019 default:
1020 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001022 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001023
Victoria Leaseda479c52012-10-15 15:24:16 -07001024 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001025 * Returns the resolution level allowed to the given PID/UID pair.
1026 *
1027 * @param pid the PID
1028 * @param uid the UID
1029 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001030 */
Victoria Lease37425c32012-10-16 16:08:48 -07001031 private int getAllowedResolutionLevel(int pid, int uid) {
1032 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1033 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1034 return RESOLUTION_LEVEL_FINE;
1035 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1036 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1037 return RESOLUTION_LEVEL_COARSE;
1038 } else {
1039 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001040 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001041 }
1042
1043 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001044 * Returns the resolution level allowed to the caller
1045 *
1046 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001047 */
Victoria Lease37425c32012-10-16 16:08:48 -07001048 private int getCallerAllowedResolutionLevel() {
1049 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1050 }
1051
1052 /**
1053 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1054 *
1055 * @param allowedResolutionLevel resolution level allowed to caller
1056 */
1057 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1058 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001059 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 }
1062
Victoria Lease37425c32012-10-16 16:08:48 -07001063 /**
1064 * Return the minimum resolution level required to use the specified location provider.
1065 *
1066 * @param provider the name of the location provider
1067 * @return minimum resolution level required for provider
1068 */
1069 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001070 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1071 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1072 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001073 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001074 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1075 LocationManager.FUSED_PROVIDER.equals(provider)) {
1076 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001077 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001078 } else {
1079 // mock providers
1080 LocationProviderInterface lp = mMockProviders.get(provider);
1081 if (lp != null) {
1082 ProviderProperties properties = lp.getProperties();
1083 if (properties != null) {
1084 if (properties.mRequiresSatellite) {
1085 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001086 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001087 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1088 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001089 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001090 }
1091 }
1092 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001093 }
Victoria Lease37425c32012-10-16 16:08:48 -07001094 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001095 }
1096
Victoria Lease37425c32012-10-16 16:08:48 -07001097 /**
1098 * Throw SecurityException if specified resolution level is insufficient to use the named
1099 * location provider.
1100 *
1101 * @param allowedResolutionLevel resolution level allowed to caller
1102 * @param providerName the name of the location provider
1103 */
1104 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1105 String providerName) {
1106 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1107 if (allowedResolutionLevel < requiredResolutionLevel) {
1108 switch (requiredResolutionLevel) {
1109 case RESOLUTION_LEVEL_FINE:
1110 throw new SecurityException("\"" + providerName + "\" location provider " +
1111 "requires ACCESS_FINE_LOCATION permission.");
1112 case RESOLUTION_LEVEL_COARSE:
1113 throw new SecurityException("\"" + providerName + "\" location provider " +
1114 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1115 default:
1116 throw new SecurityException("Insufficient permission for \"" + providerName +
1117 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001118 }
1119 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001120 }
1121
David Christie82edc9b2013-07-19 11:31:42 -07001122 /**
1123 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1124 * for battery).
1125 */
David Christie40e57822013-07-30 11:36:48 -07001126 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001127 mContext.enforceCallingOrSelfPermission(
1128 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1129 }
1130
David Christie40e57822013-07-30 11:36:48 -07001131 private void checkUpdateAppOpsAllowed() {
1132 mContext.enforceCallingOrSelfPermission(
1133 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1134 }
1135
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001136 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001137 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1138 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001139 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001140 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001141 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001142 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001143 }
1144 return -1;
1145 }
1146
David Christieb870dbf2015-06-22 12:42:53 -07001147 boolean reportLocationAccessNoThrow(
1148 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001149 int op = resolutionLevelToOp(allowedResolutionLevel);
1150 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001151 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1152 return false;
1153 }
1154 }
David Christieb870dbf2015-06-22 12:42:53 -07001155
1156 if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
1157 return false;
1158 }
1159
Dianne Hackborn35654b62013-01-14 17:38:02 -08001160 return true;
1161 }
1162
David Christieb870dbf2015-06-22 12:42:53 -07001163 boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001164 int op = resolutionLevelToOp(allowedResolutionLevel);
1165 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001166 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1167 return false;
1168 }
1169 }
David Christieb870dbf2015-06-22 12:42:53 -07001170
1171 if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
1172 return false;
1173 }
1174
Dianne Hackborn35654b62013-01-14 17:38:02 -08001175 return true;
1176 }
1177
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001178 /**
1179 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -07001180 * fused, also including ones that are not permitted to
1181 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001182 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001183 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001185 ArrayList<String> out;
1186 synchronized (mLock) {
1187 out = new ArrayList<String>(mProviders.size());
1188 for (LocationProviderInterface provider : mProviders) {
1189 String name = provider.getName();
1190 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001191 continue;
1192 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 out.add(name);
1194 }
1195 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001196
1197 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 return out;
1199 }
1200
Mike Lockwood03ca2162010-04-01 08:10:09 -07001201 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001202 * Return all providers by name, that match criteria and are optionally
1203 * enabled.
1204 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001205 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001206 @Override
1207 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001208 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001209 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001210 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -07001211 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001212 try {
1213 synchronized (mLock) {
1214 out = new ArrayList<String>(mProviders.size());
1215 for (LocationProviderInterface provider : mProviders) {
1216 String name = provider.getName();
1217 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001218 continue;
1219 }
Victoria Lease37425c32012-10-16 16:08:48 -07001220 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001221 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001222 continue;
1223 }
1224 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1225 name, provider.getProperties(), criteria)) {
1226 continue;
1227 }
1228 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001229 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001230 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001231 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001232 } finally {
1233 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001234 }
1235
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236 if (D) Log.d(TAG, "getProviders()=" + out);
1237 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001238 }
1239
1240 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001241 * Return the name of the best provider given a Criteria object.
1242 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001243 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001244 * has been deprecated as well. So this method now uses
1245 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001246 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001247 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001248 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001249 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001250
1251 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001252 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001253 result = pickBest(providers);
1254 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1255 return result;
1256 }
1257 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001258 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001259 result = pickBest(providers);
1260 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1261 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001262 }
1263
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001264 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001265 return null;
1266 }
1267
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001268 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001269 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001270 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001271 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1272 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001273 } else {
1274 return providers.get(0);
1275 }
1276 }
1277
Nick Pellye0fd6932012-07-11 10:26:13 -07001278 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001279 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1280 LocationProviderInterface p = mProvidersByName.get(provider);
1281 if (p == null) {
1282 throw new IllegalArgumentException("provider=" + provider);
1283 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001284
1285 boolean result = LocationProvider.propertiesMeetCriteria(
1286 p.getName(), p.getProperties(), criteria);
1287 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1288 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001289 }
1290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001292 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001293 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001294 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001295 boolean isEnabled = p.isEnabled();
1296 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001297 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001299 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001300 // If any provider has been disabled, clear all last locations for all providers.
1301 // This is to be on the safe side in case a provider has location derived from
1302 // this disabled provider.
1303 mLastLocation.clear();
1304 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001305 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001307 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001308 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001310 }
1311 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001312 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1313 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001314 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1315 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 }
1317 }
1318
Amith Yamasanib27528d2014-06-05 15:02:10 -07001319 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 int listeners = 0;
1321
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001322 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001323 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324
1325 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1328 if (records != null) {
1329 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001330 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 UpdateRecord record = records.get(i);
Amith Yamasanib27528d2014-06-05 15:02:10 -07001332 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001333 // Sends a notification message to the receiver
1334 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1335 if (deadReceivers == null) {
1336 deadReceivers = new ArrayList<Receiver>();
1337 }
1338 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001340 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 }
1343 }
1344
1345 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001346 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 removeUpdatesLocked(deadReceivers.get(i));
1348 }
1349 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 if (enabled) {
1352 p.enable();
1353 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001354 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 }
1356 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001357 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 }
1360
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001361 private void applyRequirementsLocked(String provider) {
1362 LocationProviderInterface p = mProvidersByName.get(provider);
1363 if (p == null) return;
1364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001366 WorkSource worksource = new WorkSource();
1367 ProviderRequest providerRequest = new ProviderRequest();
1368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001370 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001371 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001372 if (checkLocationAccess(
1373 record.mReceiver.mPid,
1374 record.mReceiver.mUid,
1375 record.mReceiver.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001376 record.mReceiver.mAllowedResolutionLevel)) {
1377 LocationRequest locationRequest = record.mRequest;
1378 providerRequest.locationRequests.add(locationRequest);
1379 if (locationRequest.getInterval() < providerRequest.interval) {
1380 providerRequest.reportLocation = true;
1381 providerRequest.interval = locationRequest.getInterval();
1382 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001383 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001384 }
1385 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001386
1387 if (providerRequest.reportLocation) {
1388 // calculate who to blame for power
1389 // This is somewhat arbitrary. We pick a threshold interval
1390 // that is slightly higher that the minimum interval, and
1391 // spread the blame across all applications with a request
1392 // under that threshold.
1393 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1394 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001395 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001396 LocationRequest locationRequest = record.mRequest;
1397 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001398 if (record.mReceiver.mWorkSource != null
1399 && record.mReceiver.mWorkSource.size() > 0
1400 && record.mReceiver.mWorkSource.getName(0) != null) {
David Christie82edc9b2013-07-19 11:31:42 -07001401 // Assign blame to another work source.
David Christiee55c9682013-08-22 10:10:34 -07001402 // Can only assign blame if the WorkSource contains names.
David Christie82edc9b2013-07-19 11:31:42 -07001403 worksource.add(record.mReceiver.mWorkSource);
1404 } else {
1405 // Assign blame to caller.
1406 worksource.add(
1407 record.mReceiver.mUid,
1408 record.mReceiver.mPackageName);
1409 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001410 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001411 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001412 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 }
1414 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001415
1416 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1417 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 }
1419
1420 private class UpdateRecord {
1421 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001422 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001424 Location mLastFixBroadcast;
1425 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426
1427 /**
1428 * Note: must be constructed with lock held.
1429 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001430 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001432 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434
1435 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1436 if (records == null) {
1437 records = new ArrayList<UpdateRecord>();
1438 mRecordsByProvider.put(provider, records);
1439 }
1440 if (!records.contains(this)) {
1441 records.add(this);
1442 }
David Christie2ff96af2014-01-30 16:09:37 -08001443
1444 // Update statistics for historical location requests by package/provider
1445 mRequestStatistics.startRequesting(
1446 mReceiver.mPackageName, provider, request.getInterval());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447 }
1448
1449 /**
David Christie2ff96af2014-01-30 16:09:37 -08001450 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001452 void disposeLocked(boolean removeReceiver) {
David Christie2ff96af2014-01-30 16:09:37 -08001453 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1454
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001455 // remove from mRecordsByProvider
1456 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1457 if (globalRecords != null) {
1458 globalRecords.remove(this);
1459 }
1460
1461 if (!removeReceiver) return; // the caller will handle the rest
1462
1463 // remove from Receiver#mUpdateRecords
1464 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1465 if (receiverRecords != null) {
1466 receiverRecords.remove(this.mProvider);
1467
1468 // and also remove the Receiver if it has no more update records
1469 if (removeReceiver && receiverRecords.size() == 0) {
1470 removeUpdatesLocked(mReceiver);
1471 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001472 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001473 }
1474
1475 @Override
1476 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001477 StringBuilder s = new StringBuilder();
1478 s.append("UpdateRecord[");
1479 s.append(mProvider);
1480 s.append(' ').append(mReceiver.mPackageName).append('(');
1481 s.append(mReceiver.mUid).append(')');
1482 s.append(' ').append(mRequest);
1483 s.append(']');
1484 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 }
1487
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001488 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001489 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001490 IBinder binder = listener.asBinder();
1491 Receiver receiver = mReceivers.get(binder);
1492 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001493 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1494 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001495 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001496 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001497 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001498 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001499 return null;
1500 }
Wen Jingcb3ab222014-03-27 13:42:59 +08001501 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001502 }
1503 return receiver;
1504 }
1505
David Christie82edc9b2013-07-19 11:31:42 -07001506 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001507 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001508 Receiver receiver = mReceivers.get(intent);
1509 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001510 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1511 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001512 mReceivers.put(intent, receiver);
1513 }
1514 return receiver;
1515 }
1516
Victoria Lease37425c32012-10-16 16:08:48 -07001517 /**
1518 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1519 * and consistency requirements.
1520 *
1521 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001522 * @return a version of request that meets the given resolution and consistency requirements
1523 * @hide
1524 */
1525 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1526 LocationRequest sanitizedRequest = new LocationRequest(request);
1527 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1528 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001529 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001530 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001531 break;
1532 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001533 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001534 break;
1535 }
1536 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001537 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1538 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001539 }
Victoria Lease37425c32012-10-16 16:08:48 -07001540 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1541 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001542 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001543 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001544 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001545 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001546 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001547 }
Victoria Lease37425c32012-10-16 16:08:48 -07001548 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001549 }
1550
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001551 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001552 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001553 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001554 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001555 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001556 String[] packages = mPackageManager.getPackagesForUid(uid);
1557 if (packages == null) {
1558 throw new SecurityException("invalid UID " + uid);
1559 }
1560 for (String pkg : packages) {
1561 if (packageName.equals(pkg)) return;
1562 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001563 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001564 }
1565
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001566 private void checkPendingIntent(PendingIntent intent) {
1567 if (intent == null) {
1568 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001569 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001570 }
1571
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001572 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07001573 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001574 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001575 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001576 } else if (intent != null && listener != null) {
1577 throw new IllegalArgumentException("cannot register both listener and intent");
1578 } else if (intent != null) {
1579 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07001580 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001581 } else {
David Christie40e57822013-07-30 11:36:48 -07001582 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001583 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001584 }
1585
Nick Pellye0fd6932012-07-11 10:26:13 -07001586 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001587 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1588 PendingIntent intent, String packageName) {
1589 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1590 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001591 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1592 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1593 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001594 WorkSource workSource = request.getWorkSource();
1595 if (workSource != null && workSource.size() > 0) {
David Christie40e57822013-07-30 11:36:48 -07001596 checkDeviceStatsAllowed();
1597 }
1598 boolean hideFromAppOps = request.getHideFromAppOps();
1599 if (hideFromAppOps) {
1600 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07001601 }
Victoria Lease37425c32012-10-16 16:08:48 -07001602 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001604 final int pid = Binder.getCallingPid();
1605 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001606 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 long identity = Binder.clearCallingIdentity();
1608 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001609 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1610 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07001611 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001612
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001613 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001614 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07001615 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07001616 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001617 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001618 } finally {
1619 Binder.restoreCallingIdentity(identity);
1620 }
1621 }
1622
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001623 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1624 int pid, int uid, String packageName) {
1625 // Figure out the provider. Either its explicitly request (legacy use cases), or
1626 // use the fused provider
1627 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1628 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001629 if (name == null) {
1630 throw new IllegalArgumentException("provider name must not be null");
1631 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001632
1633 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1634 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001635 LocationProviderInterface provider = mProvidersByName.get(name);
1636 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07001637 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001638 }
1639
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001640 UpdateRecord record = new UpdateRecord(name, request, receiver);
1641 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1642 if (oldRecord != null) {
1643 oldRecord.disposeLocked(false);
1644 }
1645
Victoria Lease09eeaec2013-02-05 11:34:13 -08001646 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001647 if (isProviderEnabled) {
1648 applyRequirementsLocked(name);
1649 } else {
1650 // Notify the listener that updates are currently disabled
1651 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 }
David Christie0b837452013-07-29 16:02:13 -07001653 // Update the monitoring here just in case multiple location requests were added to the
1654 // same receiver (this request may be high power and the initial might not have been).
1655 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 }
1657
Nick Pellye0fd6932012-07-11 10:26:13 -07001658 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001659 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1660 String packageName) {
1661 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001662
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001663 final int pid = Binder.getCallingPid();
1664 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001665
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001666 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07001667 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07001668 boolean hideFromAppOps = false;
1669 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1670 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001671
1672 // providers may use public location API's, need to clear identity
1673 long identity = Binder.clearCallingIdentity();
1674 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001675 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001676 } finally {
1677 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 }
1680 }
1681
1682 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001683 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001684
1685 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1686 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1687 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001688 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001689 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 }
1691
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001692 receiver.updateMonitoring(false);
1693
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001694 // Record which providers were associated with this listener
1695 HashSet<String> providers = new HashSet<String>();
1696 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1697 if (oldRecords != null) {
1698 // Call dispose() on the obsolete update records.
1699 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08001700 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001701 record.disposeLocked(false);
1702 }
1703 // Accumulate providers
1704 providers.addAll(oldRecords.keySet());
1705 }
1706
1707 // update provider
1708 for (String provider : providers) {
1709 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001710 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001711 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 }
1713
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001714 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 }
1716 }
1717
Dianne Hackbornc2293022013-02-06 23:14:49 -08001718 private void applyAllProviderRequirementsLocked() {
1719 for (LocationProviderInterface p : mProviders) {
1720 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001721 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001722 continue;
1723 }
1724
1725 applyRequirementsLocked(p.getName());
1726 }
1727 }
1728
Nick Pellye0fd6932012-07-11 10:26:13 -07001729 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001730 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001731 if (D) Log.d(TAG, "getLastLocation: " + request);
1732 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001733 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001734 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001735 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1736 request.getProvider());
1737 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001738
David Christieb870dbf2015-06-22 12:42:53 -07001739 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001740 final int uid = Binder.getCallingUid();
1741 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001742 try {
1743 if (mBlacklist.isBlacklisted(packageName)) {
1744 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1745 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001746 return null;
1747 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001748
David Christieb870dbf2015-06-22 12:42:53 -07001749 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001750 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1751 packageName);
1752 return null;
1753 }
1754
Victoria Leaseb711d572012-10-02 13:14:11 -07001755 synchronized (mLock) {
1756 // Figure out the provider. Either its explicitly request (deprecated API's),
1757 // or use the fused provider
1758 String name = request.getProvider();
1759 if (name == null) name = LocationManager.FUSED_PROVIDER;
1760 LocationProviderInterface provider = mProvidersByName.get(name);
1761 if (provider == null) return null;
1762
Victoria Lease09eeaec2013-02-05 11:34:13 -08001763 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001764
David Christie1b9b7b12013-04-15 15:31:11 -07001765 Location location;
1766 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1767 // Make sure that an app with coarse permissions can't get frequent location
1768 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1769 location = mLastLocationCoarseInterval.get(name);
1770 } else {
1771 location = mLastLocation.get(name);
1772 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001773 if (location == null) {
1774 return null;
1775 }
Victoria Lease37425c32012-10-16 16:08:48 -07001776 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001777 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1778 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001779 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001780 }
Victoria Lease37425c32012-10-16 16:08:48 -07001781 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001782 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001783 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001784 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001785 return null;
1786 } finally {
1787 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001788 }
1789 }
1790
1791 @Override
1792 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1793 String packageName) {
1794 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001795 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1796 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001797 checkPendingIntent(intent);
1798 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001799 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1800 request.getProvider());
1801 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001802
Victoria Lease37425c32012-10-16 16:08:48 -07001803 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001804
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001805 // geo-fence manager uses the public location API, need to clear identity
1806 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001807 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1808 // temporary measure until geofences work for secondary users
1809 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1810 return;
1811 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001812 long identity = Binder.clearCallingIdentity();
1813 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001814 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1815 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001816 } finally {
1817 Binder.restoreCallingIdentity(identity);
1818 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001819 }
1820
1821 @Override
1822 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001823 checkPendingIntent(intent);
1824 checkPackageName(packageName);
1825
1826 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1827
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001828 // geo-fence manager uses the public location API, need to clear identity
1829 long identity = Binder.clearCallingIdentity();
1830 try {
1831 mGeofenceManager.removeFence(geofence, intent);
1832 } finally {
1833 Binder.restoreCallingIdentity(identity);
1834 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001835 }
1836
1837
1838 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001839 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001840 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1841 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001842 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843
David Christieb870dbf2015-06-22 12:42:53 -07001844 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001845 final int uid = Binder.getCallingUid();
1846 final long ident = Binder.clearCallingIdentity();
1847 try {
David Christieb870dbf2015-06-22 12:42:53 -07001848 if (!checkLocationAccess(pid, uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001849 return false;
1850 }
1851 } finally {
1852 Binder.restoreCallingIdentity(ident);
1853 }
1854
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09001855 if (mGpsStatusProvider == null) {
1856 return false;
1857 }
1858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001860 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001862 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 return false;
1864 }
1865 return true;
1866 }
1867
Nick Pellye0fd6932012-07-11 10:26:13 -07001868 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001870 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001871 try {
1872 mGpsStatusProvider.removeGpsStatusListener(listener);
1873 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001874 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001875 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 }
1877 }
1878
Nick Pellye0fd6932012-07-11 10:26:13 -07001879 @Override
destradaaea8a8a62014-06-23 18:19:03 -07001880 public boolean addGpsMeasurementsListener(
1881 IGpsMeasurementsListener listener,
1882 String packageName) {
1883 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1884 checkResolutionLevelIsSufficientForProviderUse(
1885 allowedResolutionLevel,
1886 LocationManager.GPS_PROVIDER);
1887
David Christieb870dbf2015-06-22 12:42:53 -07001888 int pid = Binder.getCallingPid();
destradaaea8a8a62014-06-23 18:19:03 -07001889 int uid = Binder.getCallingUid();
1890 long identity = Binder.clearCallingIdentity();
1891 boolean hasLocationAccess;
1892 try {
David Christieb870dbf2015-06-22 12:42:53 -07001893 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
destradaaea8a8a62014-06-23 18:19:03 -07001894 } finally {
1895 Binder.restoreCallingIdentity(identity);
1896 }
1897
Wei Liu5241a4c2015-05-11 14:00:36 -07001898 if (!hasLocationAccess || mGpsMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07001899 return false;
1900 }
destradaaea8a8a62014-06-23 18:19:03 -07001901 return mGpsMeasurementsProvider.addListener(listener);
1902 }
1903
1904 @Override
destradaa6568d702014-10-27 12:47:41 -07001905 public void removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
Wei Liu5241a4c2015-05-11 14:00:36 -07001906 if (mGpsMeasurementsProvider != null) {
1907 mGpsMeasurementsProvider.removeListener(listener);
1908 }
destradaaea8a8a62014-06-23 18:19:03 -07001909 }
1910
1911 @Override
destradaa4b3e3932014-07-21 18:01:47 -07001912 public boolean addGpsNavigationMessageListener(
1913 IGpsNavigationMessageListener listener,
1914 String packageName) {
1915 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1916 checkResolutionLevelIsSufficientForProviderUse(
1917 allowedResolutionLevel,
1918 LocationManager.GPS_PROVIDER);
1919
David Christieb870dbf2015-06-22 12:42:53 -07001920 int pid = Binder.getCallingPid();
destradaa4b3e3932014-07-21 18:01:47 -07001921 int uid = Binder.getCallingUid();
1922 long identity = Binder.clearCallingIdentity();
1923 boolean hasLocationAccess;
1924 try {
David Christieb870dbf2015-06-22 12:42:53 -07001925 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
destradaa4b3e3932014-07-21 18:01:47 -07001926 } finally {
1927 Binder.restoreCallingIdentity(identity);
1928 }
1929
Wei Liu5241a4c2015-05-11 14:00:36 -07001930 if (!hasLocationAccess || mGpsNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07001931 return false;
1932 }
1933 return mGpsNavigationMessageProvider.addListener(listener);
1934 }
1935
1936 @Override
destradaa6568d702014-10-27 12:47:41 -07001937 public void removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
Wei Liu5241a4c2015-05-11 14:00:36 -07001938 if (mGpsNavigationMessageProvider != null) {
1939 mGpsNavigationMessageProvider.removeListener(listener);
1940 }
destradaa4b3e3932014-07-21 18:01:47 -07001941 }
1942
1943 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001944 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001945 if (provider == null) {
1946 // throw NullPointerException to remain compatible with previous implementation
1947 throw new NullPointerException();
1948 }
Victoria Lease37425c32012-10-16 16:08:48 -07001949 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1950 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001953 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 != PackageManager.PERMISSION_GRANTED)) {
1955 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1956 }
1957
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001958 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001959 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001960 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001961
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001962 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001963 }
1964 }
1965
Nick Pellye0fd6932012-07-11 10:26:13 -07001966 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001967 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001968 if (Binder.getCallingUid() != Process.myUid()) {
1969 throw new SecurityException(
1970 "calling sendNiResponse from outside of the system is not allowed");
1971 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001972 try {
1973 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001974 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001975 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001976 return false;
1977 }
1978 }
1979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001981 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001982 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 * accessed by the caller
1984 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001985 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001986 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001987 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08001988 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07001989 }
1990
Victoria Lease37425c32012-10-16 16:08:48 -07001991 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1992 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001994 LocationProviderInterface p;
1995 synchronized (mLock) {
1996 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 }
1998
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001999 if (p == null) return null;
2000 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002001 }
2002
Jason Monkb71218a2015-06-17 14:44:39 -04002003 /**
2004 * @return null if the provider does not exist
2005 * @throws SecurityException if the provider is not allowed to be
2006 * accessed by the caller
2007 */
2008 @Override
2009 public String getNetworkProviderPackage() {
2010 LocationProviderInterface p;
2011 synchronized (mLock) {
2012 if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2013 return null;
2014 }
2015 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2016 }
2017
2018 if (p instanceof LocationProviderProxy) {
2019 return ((LocationProviderProxy) p).getConnectedPackageName();
2020 }
2021 return null;
2022 }
2023
Nick Pellye0fd6932012-07-11 10:26:13 -07002024 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 public boolean isProviderEnabled(String provider) {
Tom O'Neilld5759432013-09-11 11:03:03 -07002026 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2027 // so we discourage its use
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002028 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2029
Victoria Lease09eeaec2013-02-05 11:34:13 -08002030 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07002031 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002032 try {
2033 synchronized (mLock) {
2034 LocationProviderInterface p = mProvidersByName.get(provider);
2035 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002036
Victoria Lease09eeaec2013-02-05 11:34:13 -08002037 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07002038 }
2039 } finally {
2040 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002041 }
2042 }
2043
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002044 /**
2045 * Returns "true" if the UID belongs to a bound location provider.
2046 *
2047 * @param uid the uid
2048 * @return true if uid belongs to a bound location provider
2049 */
2050 private boolean isUidALocationProvider(int uid) {
2051 if (uid == Process.SYSTEM_UID) {
2052 return true;
2053 }
2054 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002055 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002056 }
2057 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002058 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002059 }
2060 return false;
2061 }
2062
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002063 private void checkCallerIsProvider() {
2064 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2065 == PackageManager.PERMISSION_GRANTED) {
2066 return;
2067 }
2068
2069 // Previously we only used the INSTALL_LOCATION_PROVIDER
2070 // check. But that is system or signature
2071 // protection level which is not flexible enough for
2072 // providers installed oustide the system image. So
2073 // also allow providers with a UID matching the
2074 // currently bound package name
2075
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002076 if (isUidALocationProvider(Binder.getCallingUid())) {
2077 return;
2078 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002079
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002080 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2081 "or UID of a currently bound location provider");
2082 }
2083
David Christie1f141c12014-05-14 15:11:15 -07002084 /**
2085 * Returns true if the given package belongs to the given uid.
2086 */
2087 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002088 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002089 return false;
2090 }
David Christie1f141c12014-05-14 15:11:15 -07002091 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2092 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002093 return false;
2094 }
David Christie1f141c12014-05-14 15:11:15 -07002095 for (String name : packageNames) {
2096 if (packageName.equals(name)) {
2097 return true;
2098 }
2099 }
2100 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002101 }
2102
Nick Pellye0fd6932012-07-11 10:26:13 -07002103 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002104 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002105 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002106
Nick Pelly2eeeec22012-07-18 13:13:37 -07002107 if (!location.isComplete()) {
2108 Log.w(TAG, "Dropping incomplete location: " + location);
2109 return;
2110 }
2111
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002112 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2113 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002114 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002115 mLocationHandler.sendMessageAtFrontOfQueue(m);
2116 }
2117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002118
Laurent Tu75defb62012-11-01 16:21:52 -07002119 private static boolean shouldBroadcastSafe(
2120 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002121 // Always broadcast the first update
2122 if (lastLoc == null) {
2123 return true;
2124 }
2125
Nick Pellyf1be6862012-05-15 10:53:42 -07002126 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002127 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002128 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2129 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002130 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002131 return false;
2132 }
2133
2134 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002135 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002136 if (minDistance > 0.0) {
2137 if (loc.distanceTo(lastLoc) <= minDistance) {
2138 return false;
2139 }
2140 }
2141
Laurent Tu75defb62012-11-01 16:21:52 -07002142 // Check whether sufficient number of udpates is left
2143 if (record.mRequest.getNumUpdates() <= 0) {
2144 return false;
2145 }
2146
2147 // Check whether the expiry date has passed
2148 if (record.mRequest.getExpireAt() < now) {
2149 return false;
2150 }
2151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 return true;
2153 }
2154
Mike Lockwooda4903f22010-02-17 06:42:23 -05002155 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002156 if (D) Log.d(TAG, "incoming location: " + location);
2157
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002158 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002159 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160
Laurent Tu60ec50a2012-10-04 17:00:10 -07002161 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002162 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002163 if (p == null) return;
2164
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002165 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07002166 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2167 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002168 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002169 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002170 lastLocation = new Location(provider);
2171 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07002172 } else {
2173 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2174 if (noGPSLocation == null && lastNoGPSLocation != null) {
2175 // New location has no no-GPS location: adopt last no-GPS location. This is set
2176 // directly into location because we do not want to notify COARSE clients.
2177 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2178 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07002179 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002180 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002181
David Christie1b9b7b12013-04-15 15:31:11 -07002182 // Update last known coarse interval location if enough time has passed.
2183 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2184 if (lastLocationCoarseInterval == null) {
2185 lastLocationCoarseInterval = new Location(location);
2186 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2187 }
2188 long timeDiffNanos = location.getElapsedRealtimeNanos()
2189 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2190 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2191 lastLocationCoarseInterval.set(location);
2192 }
2193 // Don't ever return a coarse location that is more recent than the allowed update
2194 // interval (i.e. don't allow an app to keep registering and unregistering for
2195 // location updates to overcome the minimum interval).
2196 noGPSLocation =
2197 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2198
Laurent Tu60ec50a2012-10-04 17:00:10 -07002199 // Skip if there are no UpdateRecords for this provider.
2200 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2201 if (records == null || records.size() == 0) return;
2202
Victoria Lease09016ab2012-09-16 12:33:15 -07002203 // Fetch coarse location
2204 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002205 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002206 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2207 }
2208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 // Fetch latest status update time
2210 long newStatusUpdateTime = p.getStatusUpdateTime();
2211
David Christie2ff96af2014-01-30 16:09:37 -08002212 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 Bundle extras = new Bundle();
2214 int status = p.getStatus(extras);
2215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002217 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002220 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002221 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002222 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002223
Victoria Lease269518e2012-10-29 08:25:39 -07002224 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Amith Yamasanib27528d2014-06-05 15:02:10 -07002225 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002226 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002227 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002228 " (current user: " + mCurrentUserId + ", app: " +
2229 receiver.mPackageName + ")");
2230 }
2231 continue;
2232 }
2233
Nick Pelly4035f5a2012-08-17 14:43:49 -07002234 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2235 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2236 receiver.mPackageName);
2237 continue;
2238 }
2239
David Christieb870dbf2015-06-22 12:42:53 -07002240 if (!reportLocationAccessNoThrow(receiver.mPid, receiver.mUid, receiver.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002241 receiver.mAllowedResolutionLevel)) {
2242 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2243 receiver.mPackageName);
2244 continue;
2245 }
2246
Victoria Lease09016ab2012-09-16 12:33:15 -07002247 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07002248 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2249 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002250 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002251 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002252 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002253 if (notifyLocation != null) {
2254 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002255 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002256 if (lastLoc == null) {
2257 lastLoc = new Location(notifyLocation);
2258 r.mLastFixBroadcast = lastLoc;
2259 } else {
2260 lastLoc.set(notifyLocation);
2261 }
2262 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2263 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2264 receiverDead = true;
2265 }
Laurent Tu75defb62012-11-01 16:21:52 -07002266 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002267 }
2268 }
2269
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002270 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002271 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002272 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002273
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002274 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002275 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002276 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08002277 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07002278 }
2279 }
2280
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002281 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07002282 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002283 if (deadUpdateRecords == null) {
2284 deadUpdateRecords = new ArrayList<UpdateRecord>();
2285 }
2286 deadUpdateRecords.add(r);
2287 }
2288 // track dead receivers
2289 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002290 if (deadReceivers == null) {
2291 deadReceivers = new ArrayList<Receiver>();
2292 }
2293 if (!deadReceivers.contains(receiver)) {
2294 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002295 }
2296 }
2297 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002298
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002299 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002301 for (Receiver receiver : deadReceivers) {
2302 removeUpdatesLocked(receiver);
2303 }
2304 }
2305 if (deadUpdateRecords != null) {
2306 for (UpdateRecord r : deadUpdateRecords) {
2307 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002308 }
Victoria Lease8b38b292012-12-04 15:04:43 -08002309 applyRequirementsLocked(provider);
2310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002311 }
2312
2313 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08002314 public LocationWorkerHandler(Looper looper) {
2315 super(looper, null, true);
2316 }
2317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002318 @Override
2319 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002320 switch (msg.what) {
2321 case MSG_LOCATION_CHANGED:
2322 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2323 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 }
2325 }
2326 }
2327
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002328 private boolean isMockProvider(String provider) {
2329 synchronized (mLock) {
2330 return mMockProviders.containsKey(provider);
2331 }
2332 }
2333
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002334 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002335 // create a working copy of the incoming Location so that the service can modify it without
2336 // disturbing the caller's copy
2337 Location myLocation = new Location(location);
2338 String provider = myLocation.getProvider();
2339
2340 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2341 // bit if location did not come from a mock provider because passive/fused providers can
2342 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2343 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2344 myLocation.setIsFromMockProvider(true);
2345 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08002346
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002347 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08002348 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2349 if (!passive) {
2350 // notify passive provider of the new location
2351 mPassiveProvider.updateLocation(myLocation);
2352 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002353 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002355 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002356 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002357
Mike Lockwoode97ae402010-09-29 15:23:46 -04002358 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2359 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002360 public void onPackageDisappeared(String packageName, int reason) {
2361 // remove all receivers associated with this package name
2362 synchronized (mLock) {
2363 ArrayList<Receiver> deadReceivers = null;
2364
2365 for (Receiver receiver : mReceivers.values()) {
2366 if (receiver.mPackageName.equals(packageName)) {
2367 if (deadReceivers == null) {
2368 deadReceivers = new ArrayList<Receiver>();
2369 }
2370 deadReceivers.add(receiver);
2371 }
2372 }
2373
2374 // perform removal outside of mReceivers loop
2375 if (deadReceivers != null) {
2376 for (Receiver receiver : deadReceivers) {
2377 removeUpdatesLocked(receiver);
2378 }
2379 }
2380 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002381 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002382 };
2383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384 // Geocoder
2385
Nick Pellye0fd6932012-07-11 10:26:13 -07002386 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002387 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002388 return mGeocodeProvider != null;
2389 }
2390
Nick Pellye0fd6932012-07-11 10:26:13 -07002391 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002392 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002393 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002394 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002395 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2396 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002397 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002398 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002399 }
2400
Mike Lockwooda55c3212009-04-15 11:10:11 -04002401
Nick Pellye0fd6932012-07-11 10:26:13 -07002402 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002403 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002404 double lowerLeftLatitude, double lowerLeftLongitude,
2405 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002406 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002407
2408 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002409 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2410 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2411 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002412 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002413 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002414 }
2415
2416 // Mock Providers
2417
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002418 private boolean canCallerAccessMockLocation(String opPackageName) {
2419 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
2420 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002421 }
2422
Nick Pellye0fd6932012-07-11 10:26:13 -07002423 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002424 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
2425 if (!canCallerAccessMockLocation(opPackageName)) {
2426 return;
2427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002428
Mike Lockwooda4903f22010-02-17 06:42:23 -05002429 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2430 throw new IllegalArgumentException("Cannot mock the passive location provider");
2431 }
2432
Mike Lockwood86328a92009-10-23 08:38:25 -04002433 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002434 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002435 // remove the real provider if we are replacing GPS or network provider
2436 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002437 || LocationManager.NETWORK_PROVIDER.equals(name)
2438 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002439 LocationProviderInterface p = mProvidersByName.get(name);
2440 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002441 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002442 }
2443 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002444 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002445 updateProvidersLocked();
2446 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002447 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002448 }
2449
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002450 private void addTestProviderLocked(String name, ProviderProperties properties) {
2451 if (mProvidersByName.get(name) != null) {
2452 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2453 }
2454 MockProvider provider = new MockProvider(name, this, properties);
2455 addProviderLocked(provider);
2456 mMockProviders.put(name, provider);
2457 mLastLocation.put(name, null);
2458 mLastLocationCoarseInterval.put(name, null);
2459 }
2460
Nick Pellye0fd6932012-07-11 10:26:13 -07002461 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002462 public void removeTestProvider(String provider, String opPackageName) {
2463 if (!canCallerAccessMockLocation(opPackageName)) {
2464 return;
2465 }
2466
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002467 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002468
2469 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08002470 // we don't leave anything dangling.
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002471 clearTestProviderEnabled(provider, opPackageName);
2472 clearTestProviderLocation(provider, opPackageName);
2473 clearTestProviderStatus(provider, opPackageName);
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002474
You Kima6d0b6f2012-10-28 03:58:44 +09002475 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002476 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002477 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2478 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002479 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002480 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002481
2482 // reinstate real provider if available
2483 LocationProviderInterface realProvider = mRealProviders.get(provider);
2484 if (realProvider != null) {
2485 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002486 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002487 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002488 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002489 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002490 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002491 }
2492 }
2493
Nick Pellye0fd6932012-07-11 10:26:13 -07002494 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002495 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
2496 if (!canCallerAccessMockLocation(opPackageName)) {
2497 return;
2498 }
2499
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002500 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002501 MockProvider mockProvider = mMockProviders.get(provider);
2502 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002503 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2504 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002505 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2506 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002507 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002508 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002509 }
2510 }
2511
Nick Pellye0fd6932012-07-11 10:26:13 -07002512 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002513 public void clearTestProviderLocation(String provider, String opPackageName) {
2514 if (!canCallerAccessMockLocation(opPackageName)) {
2515 return;
2516 }
2517
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002518 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002519 MockProvider mockProvider = mMockProviders.get(provider);
2520 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002521 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2522 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002523 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002524 }
2525 }
2526
Nick Pellye0fd6932012-07-11 10:26:13 -07002527 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002528 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
2529 if (!canCallerAccessMockLocation(opPackageName)) {
2530 return;
2531 }
2532
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002533 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002534 MockProvider mockProvider = mMockProviders.get(provider);
2535 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002536 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2537 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002538 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002539 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002540 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002541 mEnabledProviders.add(provider);
2542 mDisabledProviders.remove(provider);
2543 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002544 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002545 mEnabledProviders.remove(provider);
2546 mDisabledProviders.add(provider);
2547 }
2548 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002549 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002550 }
2551 }
2552
Nick Pellye0fd6932012-07-11 10:26:13 -07002553 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002554 public void clearTestProviderEnabled(String provider, String opPackageName) {
2555 if (!canCallerAccessMockLocation(opPackageName)) {
2556 return;
2557 }
2558
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002559 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002560 MockProvider mockProvider = mMockProviders.get(provider);
2561 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002562 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2563 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002564 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002565 mEnabledProviders.remove(provider);
2566 mDisabledProviders.remove(provider);
2567 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002568 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002569 }
2570 }
2571
Nick Pellye0fd6932012-07-11 10:26:13 -07002572 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002573 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
2574 String opPackageName) {
2575 if (!canCallerAccessMockLocation(opPackageName)) {
2576 return;
2577 }
2578
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002579 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002580 MockProvider mockProvider = mMockProviders.get(provider);
2581 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002582 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2583 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002584 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002585 }
2586 }
2587
Nick Pellye0fd6932012-07-11 10:26:13 -07002588 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002589 public void clearTestProviderStatus(String provider, String opPackageName) {
2590 if (!canCallerAccessMockLocation(opPackageName)) {
2591 return;
2592 }
2593
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002594 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002595 MockProvider mockProvider = mMockProviders.get(provider);
2596 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002597 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2598 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002599 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002600 }
2601 }
2602
2603 private void log(String log) {
2604 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002605 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002606 }
2607 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002608
2609 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002610 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2611 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2612 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002613 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002614 + Binder.getCallingPid()
2615 + ", uid=" + Binder.getCallingUid());
2616 return;
2617 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002618
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002619 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002620 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002621 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002622 for (Receiver receiver : mReceivers.values()) {
2623 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002624 }
David Christie2ff96af2014-01-30 16:09:37 -08002625 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002626 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2627 pw.println(" " + entry.getKey() + ":");
2628 for (UpdateRecord record : entry.getValue()) {
2629 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002630 }
2631 }
David Christie2ff96af2014-01-30 16:09:37 -08002632 pw.println(" Historical Records by Provider:");
2633 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2634 : mRequestStatistics.statistics.entrySet()) {
2635 PackageProviderKey key = entry.getKey();
2636 PackageStatistics stats = entry.getValue();
2637 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
2638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002639 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002640 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2641 String provider = entry.getKey();
2642 Location location = entry.getValue();
2643 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002645
David Christie1b9b7b12013-04-15 15:31:11 -07002646 pw.println(" Last Known Locations Coarse Intervals:");
2647 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2648 String provider = entry.getKey();
2649 Location location = entry.getValue();
2650 pw.println(" " + provider + ": " + location);
2651 }
2652
Nick Pellye0fd6932012-07-11 10:26:13 -07002653 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002655 if (mEnabledProviders.size() > 0) {
2656 pw.println(" Enabled Providers:");
2657 for (String i : mEnabledProviders) {
2658 pw.println(" " + i);
2659 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002661 }
2662 if (mDisabledProviders.size() > 0) {
2663 pw.println(" Disabled Providers:");
2664 for (String i : mDisabledProviders) {
2665 pw.println(" " + i);
2666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002667 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002668 pw.append(" ");
2669 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002670 if (mMockProviders.size() > 0) {
2671 pw.println(" Mock Providers:");
2672 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002673 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002674 }
2675 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002676
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002677 pw.append(" fudger: ");
2678 mLocationFudger.dump(fd, pw, args);
2679
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002680 if (args.length > 0 && "short".equals(args[0])) {
2681 return;
2682 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002683 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002684 pw.print(provider.getName() + " Internal State");
2685 if (provider instanceof LocationProviderProxy) {
2686 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2687 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002688 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002689 pw.println(":");
2690 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002691 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002692 }
2693 }
2694}