blob: 468ead0e9c928697d4f60aac2f1d2e27e0b6275b [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
destradaa6e2fe752015-06-23 17:25:53 -0700545 // bind to hardware activity recognition
546 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
547 ActivityRecognitionHardware activityRecognitionHardware = null;
548 if (activityRecognitionHardwareIsSupported) {
549 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700550 } else {
551 Slog.e(TAG, "Hardware Activity-Recognition not supported.");
552 }
destradaa6e2fe752015-06-23 17:25:53 -0700553 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
554 mContext,
555 mLocationHandler,
556 activityRecognitionHardwareIsSupported,
557 activityRecognitionHardware,
558 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
559 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
560 com.android.internal.R.array.config_locationProviderPackageNames);
561 if (proxy == null) {
562 Slog.e(TAG, "Unable to bind ActivityRecognitionProxy.");
563 }
destradaaa4fa3b52014-07-09 10:46:39 -0700564
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900565 String[] testProviderStrings = resources.getStringArray(
566 com.android.internal.R.array.config_testLocationProviders);
567 for (String testProviderString : testProviderStrings) {
568 String fragments[] = testProviderString.split(",");
569 String name = fragments[0].trim();
570 if (mProvidersByName.get(name) != null) {
571 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
572 }
573 ProviderProperties properties = new ProviderProperties(
574 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
575 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
576 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
577 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
578 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
579 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
580 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
581 Integer.parseInt(fragments[8]) /* powerRequirement */,
582 Integer.parseInt(fragments[9]) /* accuracy */);
583 addTestProviderLocked(name, properties);
584 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700585 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700588 * Called when the device's active user changes.
589 * @param userId the new active user's UserId
590 */
591 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800592 if (mCurrentUserId == userId) {
593 return;
594 }
Victoria Lease83762d22012-10-03 13:51:17 -0700595 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800596 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700597 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700598 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700599 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700600 for (LocationProviderInterface p : mProviders) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700601 updateProviderListenersLocked(p.getName(), false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700602 }
Victoria Lease38389b62012-09-30 11:44:22 -0700603 mCurrentUserId = userId;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700604 updateUserProfiles(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700605 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700606 }
607 }
608
609 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
611 * location updates.
612 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700613 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700614 final int mUid; // uid of receiver
615 final int mPid; // pid of receiver
616 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700617 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 final ILocationListener mListener;
620 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700621 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700622 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700624
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400625 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700626
David Christie0b837452013-07-29 16:02:13 -0700627 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700628 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700629 // True if app ops has started monitoring this receiver for high power (gps) locations.
630 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700631 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700632 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700634 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700635 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700638 if (listener != null) {
639 mKey = listener.asBinder();
640 } else {
641 mKey = intent;
642 }
Victoria Lease37425c32012-10-16 16:08:48 -0700643 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700644 mUid = uid;
645 mPid = pid;
646 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700647 if (workSource != null && workSource.size() <= 0) {
648 workSource = null;
649 }
650 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700651 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700652
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700653 updateMonitoring(true);
654
Victoria Lease0aa28602013-05-29 15:28:26 -0700655 // construct/configure wakelock
656 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700657 if (workSource == null) {
658 workSource = new WorkSource(mUid, mPackageName);
659 }
660 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 }
662
663 @Override
664 public boolean equals(Object otherObj) {
665 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700666 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 }
668 return false;
669 }
670
671 @Override
672 public int hashCode() {
673 return mKey.hashCode();
674 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400675
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 @Override
677 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700678 StringBuilder s = new StringBuilder();
679 s.append("Reciever[");
680 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700682 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700684 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700686 for (String p : mUpdateRecords.keySet()) {
687 s.append(" ").append(mUpdateRecords.get(p).toString());
688 }
689 s.append("]");
690 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 }
692
David Christie15b31912013-08-13 15:54:32 -0700693 /**
694 * Update AppOp monitoring for this receiver.
695 *
696 * @param allow If true receiver is currently active, if false it's been removed.
697 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700698 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700699 if (mHideFromAppOps) {
700 return;
701 }
702
David Christie15b31912013-08-13 15:54:32 -0700703 boolean requestingLocation = false;
704 boolean requestingHighPowerLocation = false;
705 if (allow) {
706 // See if receiver has any enabled update records. Also note if any update records
707 // are high power (has a high power provider with an interval under a threshold).
708 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
709 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
710 requestingLocation = true;
711 LocationProviderInterface locationProvider
David Christie2ff96af2014-01-30 16:09:37 -0800712 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -0700713 ProviderProperties properties = locationProvider != null
714 ? locationProvider.getProperties() : null;
715 if (properties != null
716 && properties.mPowerRequirement == Criteria.POWER_HIGH
717 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
718 requestingHighPowerLocation = true;
719 break;
720 }
721 }
722 }
723 }
724
David Christie0b837452013-07-29 16:02:13 -0700725 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700726 mOpMonitoring = updateMonitoring(
727 requestingLocation,
728 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700729 AppOpsManager.OP_MONITOR_LOCATION);
730
731 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700732 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700733 mOpHighPowerMonitoring = updateMonitoring(
734 requestingHighPowerLocation,
735 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700736 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700737 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700738 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700739 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
740 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
741 }
David Christie0b837452013-07-29 16:02:13 -0700742 }
743
744 /**
745 * Update AppOps monitoring for a single location request and op type.
746 *
747 * @param allowMonitoring True if monitoring is allowed for this request/op.
748 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
749 * @param op AppOps code for the op to update.
750 * @return True if monitoring is on for this request/op after updating.
751 */
752 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
753 int op) {
754 if (!currentlyMonitoring) {
755 if (allowMonitoring) {
756 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
757 == AppOpsManager.MODE_ALLOWED;
758 }
759 } else {
760 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
761 != AppOpsManager.MODE_ALLOWED) {
762 mAppOps.finishOp(op, mUid, mPackageName);
763 return false;
764 }
765 }
766
767 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700768 }
769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 public boolean isListener() {
771 return mListener != null;
772 }
773
774 public boolean isPendingIntent() {
775 return mPendingIntent != null;
776 }
777
778 public ILocationListener getListener() {
779 if (mListener != null) {
780 return mListener;
781 }
782 throw new IllegalStateException("Request for non-existent listener");
783 }
784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
786 if (mListener != null) {
787 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700788 synchronized (this) {
789 // synchronize to ensure incrementPendingBroadcastsLocked()
790 // is called before decrementPendingBroadcasts()
791 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700792 // call this after broadcasting so we do not increment
793 // if we throw an exeption.
794 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700795 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 } catch (RemoteException e) {
797 return false;
798 }
799 } else {
800 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800801 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
803 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700804 synchronized (this) {
805 // synchronize to ensure incrementPendingBroadcastsLocked()
806 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700807 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700808 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700809 // call this after broadcasting so we do not increment
810 // if we throw an exeption.
811 incrementPendingBroadcastsLocked();
812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 } catch (PendingIntent.CanceledException e) {
814 return false;
815 }
816 }
817 return true;
818 }
819
820 public boolean callLocationChangedLocked(Location location) {
821 if (mListener != null) {
822 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700823 synchronized (this) {
824 // synchronize to ensure incrementPendingBroadcastsLocked()
825 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800826 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700827 // call this after broadcasting so we do not increment
828 // if we throw an exeption.
829 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700830 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 } catch (RemoteException e) {
832 return false;
833 }
834 } else {
835 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800836 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700838 synchronized (this) {
839 // synchronize to ensure incrementPendingBroadcastsLocked()
840 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700841 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700842 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700843 // call this after broadcasting so we do not increment
844 // if we throw an exeption.
845 incrementPendingBroadcastsLocked();
846 }
847 } catch (PendingIntent.CanceledException e) {
848 return false;
849 }
850 }
851 return true;
852 }
853
854 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -0700855 // First update AppOp monitoring.
856 // An app may get/lose location access as providers are enabled/disabled.
857 updateMonitoring(true);
858
Mike Lockwood48f17512009-04-23 09:12:08 -0700859 if (mListener != null) {
860 try {
861 synchronized (this) {
862 // synchronize to ensure incrementPendingBroadcastsLocked()
863 // is called before decrementPendingBroadcasts()
864 if (enabled) {
865 mListener.onProviderEnabled(provider);
866 } else {
867 mListener.onProviderDisabled(provider);
868 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700869 // call this after broadcasting so we do not increment
870 // if we throw an exeption.
871 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700872 }
873 } catch (RemoteException e) {
874 return false;
875 }
876 } else {
877 Intent providerIntent = new Intent();
878 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
879 try {
880 synchronized (this) {
881 // synchronize to ensure incrementPendingBroadcastsLocked()
882 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700883 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700884 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700885 // call this after broadcasting so we do not increment
886 // if we throw an exeption.
887 incrementPendingBroadcastsLocked();
888 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 } catch (PendingIntent.CanceledException e) {
890 return false;
891 }
892 }
893 return true;
894 }
895
Nick Pellyf1be6862012-05-15 10:53:42 -0700896 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700898 if (D) Log.d(TAG, "Location listener died");
899
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400900 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 removeUpdatesLocked(this);
902 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700903 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700904 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700905 }
906 }
907
Nick Pellye0fd6932012-07-11 10:26:13 -0700908 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700909 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
910 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400911 synchronized (this) {
912 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700913 }
914 }
915
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400916 // this must be called while synchronized by caller in a synchronized block
917 // containing the sending of the broadcaset
918 private void incrementPendingBroadcastsLocked() {
919 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700920 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400921 }
922 }
923
924 private void decrementPendingBroadcastsLocked() {
925 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700926 if (mWakeLock.isHeld()) {
927 mWakeLock.release();
928 }
929 }
930 }
931
932 public void clearPendingBroadcastsLocked() {
933 if (mPendingBroadcasts > 0) {
934 mPendingBroadcasts = 0;
935 if (mWakeLock.isHeld()) {
936 mWakeLock.release();
937 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700938 }
939 }
940 }
941
Nick Pellye0fd6932012-07-11 10:26:13 -0700942 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700943 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700944 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400945 //the receiver list if it is not found. If it is not found then the
946 //LocationListener was removed when it had a pending broadcast and should
947 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700948 synchronized (mLock) {
949 IBinder binder = listener.asBinder();
950 Receiver receiver = mReceivers.get(binder);
951 if (receiver != null) {
952 synchronized (receiver) {
953 // so wakelock calls will succeed
954 long identity = Binder.clearCallingIdentity();
955 receiver.decrementPendingBroadcastsLocked();
956 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -0800957 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700958 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 }
960 }
961
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700962 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400963 mProviders.add(provider);
964 mProvidersByName.put(provider.getName(), provider);
965 }
966
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700967 private void removeProviderLocked(LocationProviderInterface provider) {
968 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400969 mProviders.remove(provider);
970 mProvidersByName.remove(provider.getName());
971 }
972
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800973 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800974 * Returns "true" if access to the specified location provider is allowed by the current
975 * user's settings. Access to all location providers is forbidden to non-location-provider
976 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800977 *
978 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800979 * @return
980 */
Victoria Lease09eeaec2013-02-05 11:34:13 -0800981 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 if (mEnabledProviders.contains(provider)) {
983 return true;
984 }
985 if (mDisabledProviders.contains(provider)) {
986 return false;
987 }
988 // Use system settings
989 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990
Victoria Leaseb711d572012-10-02 13:14:11 -0700991 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 }
993
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700994 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -0800995 * Returns "true" if access to the specified location provider is allowed by the specified
996 * user's settings. Access to all location providers is forbidden to non-location-provider
997 * processes belonging to background users.
998 *
999 * @param provider the name of the location provider
1000 * @param uid the requestor's UID
1001 * @return
1002 */
1003 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001004 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001005 return false;
1006 }
1007 return isAllowedByCurrentUserSettingsLocked(provider);
1008 }
1009
1010 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001011 * Returns the permission string associated with the specified resolution level.
1012 *
1013 * @param resolutionLevel the resolution level
1014 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001015 */
Victoria Lease37425c32012-10-16 16:08:48 -07001016 private String getResolutionPermission(int resolutionLevel) {
1017 switch (resolutionLevel) {
1018 case RESOLUTION_LEVEL_FINE:
1019 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1020 case RESOLUTION_LEVEL_COARSE:
1021 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1022 default:
1023 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001025 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001026
Victoria Leaseda479c52012-10-15 15:24:16 -07001027 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001028 * Returns the resolution level allowed to the given PID/UID pair.
1029 *
1030 * @param pid the PID
1031 * @param uid the UID
1032 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001033 */
Victoria Lease37425c32012-10-16 16:08:48 -07001034 private int getAllowedResolutionLevel(int pid, int uid) {
1035 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1036 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1037 return RESOLUTION_LEVEL_FINE;
1038 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1039 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1040 return RESOLUTION_LEVEL_COARSE;
1041 } else {
1042 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001043 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001044 }
1045
1046 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001047 * Returns the resolution level allowed to the caller
1048 *
1049 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001050 */
Victoria Lease37425c32012-10-16 16:08:48 -07001051 private int getCallerAllowedResolutionLevel() {
1052 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1053 }
1054
1055 /**
1056 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1057 *
1058 * @param allowedResolutionLevel resolution level allowed to caller
1059 */
1060 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1061 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001062 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1063 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 }
1065
Victoria Lease37425c32012-10-16 16:08:48 -07001066 /**
1067 * Return the minimum resolution level required to use the specified location provider.
1068 *
1069 * @param provider the name of the location provider
1070 * @return minimum resolution level required for provider
1071 */
1072 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001073 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1074 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1075 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001076 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001077 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1078 LocationManager.FUSED_PROVIDER.equals(provider)) {
1079 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001080 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001081 } else {
1082 // mock providers
1083 LocationProviderInterface lp = mMockProviders.get(provider);
1084 if (lp != null) {
1085 ProviderProperties properties = lp.getProperties();
1086 if (properties != null) {
1087 if (properties.mRequiresSatellite) {
1088 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001089 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001090 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1091 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001092 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001093 }
1094 }
1095 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001096 }
Victoria Lease37425c32012-10-16 16:08:48 -07001097 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001098 }
1099
Victoria Lease37425c32012-10-16 16:08:48 -07001100 /**
1101 * Throw SecurityException if specified resolution level is insufficient to use the named
1102 * location provider.
1103 *
1104 * @param allowedResolutionLevel resolution level allowed to caller
1105 * @param providerName the name of the location provider
1106 */
1107 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1108 String providerName) {
1109 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1110 if (allowedResolutionLevel < requiredResolutionLevel) {
1111 switch (requiredResolutionLevel) {
1112 case RESOLUTION_LEVEL_FINE:
1113 throw new SecurityException("\"" + providerName + "\" location provider " +
1114 "requires ACCESS_FINE_LOCATION permission.");
1115 case RESOLUTION_LEVEL_COARSE:
1116 throw new SecurityException("\"" + providerName + "\" location provider " +
1117 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1118 default:
1119 throw new SecurityException("Insufficient permission for \"" + providerName +
1120 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001121 }
1122 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001123 }
1124
David Christie82edc9b2013-07-19 11:31:42 -07001125 /**
1126 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1127 * for battery).
1128 */
David Christie40e57822013-07-30 11:36:48 -07001129 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001130 mContext.enforceCallingOrSelfPermission(
1131 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1132 }
1133
David Christie40e57822013-07-30 11:36:48 -07001134 private void checkUpdateAppOpsAllowed() {
1135 mContext.enforceCallingOrSelfPermission(
1136 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1137 }
1138
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001139 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001140 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1141 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001142 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001143 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001144 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001145 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001146 }
1147 return -1;
1148 }
1149
David Christieb870dbf2015-06-22 12:42:53 -07001150 boolean reportLocationAccessNoThrow(
1151 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001152 int op = resolutionLevelToOp(allowedResolutionLevel);
1153 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001154 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1155 return false;
1156 }
1157 }
David Christieb870dbf2015-06-22 12:42:53 -07001158
1159 if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
1160 return false;
1161 }
1162
Dianne Hackborn35654b62013-01-14 17:38:02 -08001163 return true;
1164 }
1165
David Christieb870dbf2015-06-22 12:42:53 -07001166 boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001167 int op = resolutionLevelToOp(allowedResolutionLevel);
1168 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001169 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1170 return false;
1171 }
1172 }
David Christieb870dbf2015-06-22 12:42:53 -07001173
1174 if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
1175 return false;
1176 }
1177
Dianne Hackborn35654b62013-01-14 17:38:02 -08001178 return true;
1179 }
1180
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001181 /**
1182 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -07001183 * fused, also including ones that are not permitted to
1184 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001185 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001186 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001188 ArrayList<String> out;
1189 synchronized (mLock) {
1190 out = new ArrayList<String>(mProviders.size());
1191 for (LocationProviderInterface provider : mProviders) {
1192 String name = provider.getName();
1193 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001194 continue;
1195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 out.add(name);
1197 }
1198 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001199
1200 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 return out;
1202 }
1203
Mike Lockwood03ca2162010-04-01 08:10:09 -07001204 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001205 * Return all providers by name, that match criteria and are optionally
1206 * enabled.
1207 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001208 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001209 @Override
1210 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001211 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001212 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001213 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -07001214 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001215 try {
1216 synchronized (mLock) {
1217 out = new ArrayList<String>(mProviders.size());
1218 for (LocationProviderInterface provider : mProviders) {
1219 String name = provider.getName();
1220 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001221 continue;
1222 }
Victoria Lease37425c32012-10-16 16:08:48 -07001223 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001224 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001225 continue;
1226 }
1227 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1228 name, provider.getProperties(), criteria)) {
1229 continue;
1230 }
1231 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001232 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001233 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001234 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001235 } finally {
1236 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001237 }
1238
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001239 if (D) Log.d(TAG, "getProviders()=" + out);
1240 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001241 }
1242
1243 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001244 * Return the name of the best provider given a Criteria object.
1245 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001246 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001247 * has been deprecated as well. So this method now uses
1248 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001249 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001250 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001251 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001252 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001253
1254 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001255 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001256 result = pickBest(providers);
1257 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1258 return result;
1259 }
1260 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001261 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001262 result = pickBest(providers);
1263 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1264 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001265 }
1266
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001267 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001268 return null;
1269 }
1270
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001271 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001272 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001273 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001274 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1275 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001276 } else {
1277 return providers.get(0);
1278 }
1279 }
1280
Nick Pellye0fd6932012-07-11 10:26:13 -07001281 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001282 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1283 LocationProviderInterface p = mProvidersByName.get(provider);
1284 if (p == null) {
1285 throw new IllegalArgumentException("provider=" + provider);
1286 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001287
1288 boolean result = LocationProvider.propertiesMeetCriteria(
1289 p.getName(), p.getProperties(), criteria);
1290 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1291 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001292 }
1293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001295 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001296 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001297 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 boolean isEnabled = p.isEnabled();
1299 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001300 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001302 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001303 // If any provider has been disabled, clear all last locations for all providers.
1304 // This is to be on the safe side in case a provider has location derived from
1305 // this disabled provider.
1306 mLastLocation.clear();
1307 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001308 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001310 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001311 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001313 }
1314 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001315 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1316 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001317 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1318 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 }
1320 }
1321
Amith Yamasanib27528d2014-06-05 15:02:10 -07001322 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 int listeners = 0;
1324
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001325 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001326 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327
1328 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1331 if (records != null) {
1332 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001333 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 UpdateRecord record = records.get(i);
Amith Yamasanib27528d2014-06-05 15:02:10 -07001335 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001336 // Sends a notification message to the receiver
1337 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1338 if (deadReceivers == null) {
1339 deadReceivers = new ArrayList<Receiver>();
1340 }
1341 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001343 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 }
1346 }
1347
1348 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001349 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 removeUpdatesLocked(deadReceivers.get(i));
1351 }
1352 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 if (enabled) {
1355 p.enable();
1356 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001357 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358 }
1359 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 }
1363
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001364 private void applyRequirementsLocked(String provider) {
1365 LocationProviderInterface p = mProvidersByName.get(provider);
1366 if (p == null) return;
1367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001368 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001369 WorkSource worksource = new WorkSource();
1370 ProviderRequest providerRequest = new ProviderRequest();
1371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001373 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001374 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001375 if (checkLocationAccess(
1376 record.mReceiver.mPid,
1377 record.mReceiver.mUid,
1378 record.mReceiver.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001379 record.mReceiver.mAllowedResolutionLevel)) {
1380 LocationRequest locationRequest = record.mRequest;
1381 providerRequest.locationRequests.add(locationRequest);
1382 if (locationRequest.getInterval() < providerRequest.interval) {
1383 providerRequest.reportLocation = true;
1384 providerRequest.interval = locationRequest.getInterval();
1385 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001386 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001387 }
1388 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001389
1390 if (providerRequest.reportLocation) {
1391 // calculate who to blame for power
1392 // This is somewhat arbitrary. We pick a threshold interval
1393 // that is slightly higher that the minimum interval, and
1394 // spread the blame across all applications with a request
1395 // under that threshold.
1396 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1397 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001398 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001399 LocationRequest locationRequest = record.mRequest;
1400 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001401 if (record.mReceiver.mWorkSource != null
1402 && record.mReceiver.mWorkSource.size() > 0
1403 && record.mReceiver.mWorkSource.getName(0) != null) {
David Christie82edc9b2013-07-19 11:31:42 -07001404 // Assign blame to another work source.
David Christiee55c9682013-08-22 10:10:34 -07001405 // Can only assign blame if the WorkSource contains names.
David Christie82edc9b2013-07-19 11:31:42 -07001406 worksource.add(record.mReceiver.mWorkSource);
1407 } else {
1408 // Assign blame to caller.
1409 worksource.add(
1410 record.mReceiver.mUid,
1411 record.mReceiver.mPackageName);
1412 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001413 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001414 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001415 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 }
1417 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001418
1419 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1420 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 }
1422
1423 private class UpdateRecord {
1424 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001425 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001427 Location mLastFixBroadcast;
1428 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429
1430 /**
1431 * Note: must be constructed with lock held.
1432 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001433 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001435 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437
1438 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1439 if (records == null) {
1440 records = new ArrayList<UpdateRecord>();
1441 mRecordsByProvider.put(provider, records);
1442 }
1443 if (!records.contains(this)) {
1444 records.add(this);
1445 }
David Christie2ff96af2014-01-30 16:09:37 -08001446
1447 // Update statistics for historical location requests by package/provider
1448 mRequestStatistics.startRequesting(
1449 mReceiver.mPackageName, provider, request.getInterval());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450 }
1451
1452 /**
David Christie2ff96af2014-01-30 16:09:37 -08001453 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001455 void disposeLocked(boolean removeReceiver) {
David Christie2ff96af2014-01-30 16:09:37 -08001456 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1457
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001458 // remove from mRecordsByProvider
1459 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1460 if (globalRecords != null) {
1461 globalRecords.remove(this);
1462 }
1463
1464 if (!removeReceiver) return; // the caller will handle the rest
1465
1466 // remove from Receiver#mUpdateRecords
1467 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1468 if (receiverRecords != null) {
1469 receiverRecords.remove(this.mProvider);
1470
1471 // and also remove the Receiver if it has no more update records
1472 if (removeReceiver && receiverRecords.size() == 0) {
1473 removeUpdatesLocked(mReceiver);
1474 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001475 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001476 }
1477
1478 @Override
1479 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001480 StringBuilder s = new StringBuilder();
1481 s.append("UpdateRecord[");
1482 s.append(mProvider);
1483 s.append(' ').append(mReceiver.mPackageName).append('(');
1484 s.append(mReceiver.mUid).append(')');
1485 s.append(' ').append(mRequest);
1486 s.append(']');
1487 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 }
1490
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001491 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001492 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001493 IBinder binder = listener.asBinder();
1494 Receiver receiver = mReceivers.get(binder);
1495 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001496 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1497 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001498 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001499 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001500 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001501 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001502 return null;
1503 }
Wen Jingcb3ab222014-03-27 13:42:59 +08001504 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001505 }
1506 return receiver;
1507 }
1508
David Christie82edc9b2013-07-19 11:31:42 -07001509 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001510 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001511 Receiver receiver = mReceivers.get(intent);
1512 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001513 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1514 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001515 mReceivers.put(intent, receiver);
1516 }
1517 return receiver;
1518 }
1519
Victoria Lease37425c32012-10-16 16:08:48 -07001520 /**
1521 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1522 * and consistency requirements.
1523 *
1524 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001525 * @return a version of request that meets the given resolution and consistency requirements
1526 * @hide
1527 */
1528 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1529 LocationRequest sanitizedRequest = new LocationRequest(request);
1530 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1531 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001532 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001533 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001534 break;
1535 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001536 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001537 break;
1538 }
1539 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001540 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1541 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001542 }
Victoria Lease37425c32012-10-16 16:08:48 -07001543 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1544 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001545 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001546 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001547 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001548 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001549 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001550 }
Victoria Lease37425c32012-10-16 16:08:48 -07001551 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001552 }
1553
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001554 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001555 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001556 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001557 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001558 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001559 String[] packages = mPackageManager.getPackagesForUid(uid);
1560 if (packages == null) {
1561 throw new SecurityException("invalid UID " + uid);
1562 }
1563 for (String pkg : packages) {
1564 if (packageName.equals(pkg)) return;
1565 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001566 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001567 }
1568
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001569 private void checkPendingIntent(PendingIntent intent) {
1570 if (intent == null) {
1571 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001572 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001573 }
1574
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001575 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07001576 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001577 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001578 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001579 } else if (intent != null && listener != null) {
1580 throw new IllegalArgumentException("cannot register both listener and intent");
1581 } else if (intent != null) {
1582 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07001583 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001584 } else {
David Christie40e57822013-07-30 11:36:48 -07001585 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001586 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001587 }
1588
Nick Pellye0fd6932012-07-11 10:26:13 -07001589 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001590 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1591 PendingIntent intent, String packageName) {
1592 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1593 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001594 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1595 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1596 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001597 WorkSource workSource = request.getWorkSource();
1598 if (workSource != null && workSource.size() > 0) {
David Christie40e57822013-07-30 11:36:48 -07001599 checkDeviceStatsAllowed();
1600 }
1601 boolean hideFromAppOps = request.getHideFromAppOps();
1602 if (hideFromAppOps) {
1603 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07001604 }
Victoria Lease37425c32012-10-16 16:08:48 -07001605 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001607 final int pid = Binder.getCallingPid();
1608 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001609 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 long identity = Binder.clearCallingIdentity();
1611 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001612 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1613 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07001614 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001615
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001616 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001617 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07001618 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07001619 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001620 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 } finally {
1622 Binder.restoreCallingIdentity(identity);
1623 }
1624 }
1625
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001626 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1627 int pid, int uid, String packageName) {
1628 // Figure out the provider. Either its explicitly request (legacy use cases), or
1629 // use the fused provider
1630 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1631 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001632 if (name == null) {
1633 throw new IllegalArgumentException("provider name must not be null");
1634 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001635
1636 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1637 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001638 LocationProviderInterface provider = mProvidersByName.get(name);
1639 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07001640 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001641 }
1642
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001643 UpdateRecord record = new UpdateRecord(name, request, receiver);
1644 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1645 if (oldRecord != null) {
1646 oldRecord.disposeLocked(false);
1647 }
1648
Victoria Lease09eeaec2013-02-05 11:34:13 -08001649 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001650 if (isProviderEnabled) {
1651 applyRequirementsLocked(name);
1652 } else {
1653 // Notify the listener that updates are currently disabled
1654 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 }
David Christie0b837452013-07-29 16:02:13 -07001656 // Update the monitoring here just in case multiple location requests were added to the
1657 // same receiver (this request may be high power and the initial might not have been).
1658 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 }
1660
Nick Pellye0fd6932012-07-11 10:26:13 -07001661 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001662 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1663 String packageName) {
1664 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001665
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001666 final int pid = Binder.getCallingPid();
1667 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001668
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001669 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07001670 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07001671 boolean hideFromAppOps = false;
1672 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1673 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001674
1675 // providers may use public location API's, need to clear identity
1676 long identity = Binder.clearCallingIdentity();
1677 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001678 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001679 } finally {
1680 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 }
1683 }
1684
1685 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001686 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001687
1688 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1689 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1690 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001691 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001692 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 }
1694
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001695 receiver.updateMonitoring(false);
1696
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001697 // Record which providers were associated with this listener
1698 HashSet<String> providers = new HashSet<String>();
1699 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1700 if (oldRecords != null) {
1701 // Call dispose() on the obsolete update records.
1702 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08001703 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001704 record.disposeLocked(false);
1705 }
1706 // Accumulate providers
1707 providers.addAll(oldRecords.keySet());
1708 }
1709
1710 // update provider
1711 for (String provider : providers) {
1712 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001713 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001714 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 }
1716
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001717 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 }
1719 }
1720
Dianne Hackbornc2293022013-02-06 23:14:49 -08001721 private void applyAllProviderRequirementsLocked() {
1722 for (LocationProviderInterface p : mProviders) {
1723 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001724 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001725 continue;
1726 }
1727
1728 applyRequirementsLocked(p.getName());
1729 }
1730 }
1731
Nick Pellye0fd6932012-07-11 10:26:13 -07001732 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001733 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001734 if (D) Log.d(TAG, "getLastLocation: " + request);
1735 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001736 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001737 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001738 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1739 request.getProvider());
1740 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001741
David Christieb870dbf2015-06-22 12:42:53 -07001742 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001743 final int uid = Binder.getCallingUid();
1744 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001745 try {
1746 if (mBlacklist.isBlacklisted(packageName)) {
1747 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1748 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001749 return null;
1750 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001751
David Christieb870dbf2015-06-22 12:42:53 -07001752 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001753 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1754 packageName);
1755 return null;
1756 }
1757
Victoria Leaseb711d572012-10-02 13:14:11 -07001758 synchronized (mLock) {
1759 // Figure out the provider. Either its explicitly request (deprecated API's),
1760 // or use the fused provider
1761 String name = request.getProvider();
1762 if (name == null) name = LocationManager.FUSED_PROVIDER;
1763 LocationProviderInterface provider = mProvidersByName.get(name);
1764 if (provider == null) return null;
1765
Victoria Lease09eeaec2013-02-05 11:34:13 -08001766 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001767
David Christie1b9b7b12013-04-15 15:31:11 -07001768 Location location;
1769 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1770 // Make sure that an app with coarse permissions can't get frequent location
1771 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1772 location = mLastLocationCoarseInterval.get(name);
1773 } else {
1774 location = mLastLocation.get(name);
1775 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001776 if (location == null) {
1777 return null;
1778 }
Victoria Lease37425c32012-10-16 16:08:48 -07001779 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001780 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1781 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001782 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001783 }
Victoria Lease37425c32012-10-16 16:08:48 -07001784 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001785 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001786 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001787 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001788 return null;
1789 } finally {
1790 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001791 }
1792 }
1793
1794 @Override
1795 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1796 String packageName) {
1797 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001798 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1799 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001800 checkPendingIntent(intent);
1801 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001802 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1803 request.getProvider());
1804 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001805
Victoria Lease37425c32012-10-16 16:08:48 -07001806 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001807
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001808 // geo-fence manager uses the public location API, need to clear identity
1809 int uid = Binder.getCallingUid();
Victoria Lease56e675b2012-11-05 19:25:06 -08001810 if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
1811 // temporary measure until geofences work for secondary users
1812 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1813 return;
1814 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001815 long identity = Binder.clearCallingIdentity();
1816 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001817 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1818 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001819 } finally {
1820 Binder.restoreCallingIdentity(identity);
1821 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001822 }
1823
1824 @Override
1825 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001826 checkPendingIntent(intent);
1827 checkPackageName(packageName);
1828
1829 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1830
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001831 // geo-fence manager uses the public location API, need to clear identity
1832 long identity = Binder.clearCallingIdentity();
1833 try {
1834 mGeofenceManager.removeFence(geofence, intent);
1835 } finally {
1836 Binder.restoreCallingIdentity(identity);
1837 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001838 }
1839
1840
1841 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001842 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001843 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1844 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001845 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001846
David Christieb870dbf2015-06-22 12:42:53 -07001847 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001848 final int uid = Binder.getCallingUid();
1849 final long ident = Binder.clearCallingIdentity();
1850 try {
David Christieb870dbf2015-06-22 12:42:53 -07001851 if (!checkLocationAccess(pid, uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001852 return false;
1853 }
1854 } finally {
1855 Binder.restoreCallingIdentity(ident);
1856 }
1857
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09001858 if (mGpsStatusProvider == null) {
1859 return false;
1860 }
1861
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001863 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001865 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 return false;
1867 }
1868 return true;
1869 }
1870
Nick Pellye0fd6932012-07-11 10:26:13 -07001871 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001873 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001874 try {
1875 mGpsStatusProvider.removeGpsStatusListener(listener);
1876 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001877 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 }
1880 }
1881
Nick Pellye0fd6932012-07-11 10:26:13 -07001882 @Override
destradaaea8a8a62014-06-23 18:19:03 -07001883 public boolean addGpsMeasurementsListener(
1884 IGpsMeasurementsListener listener,
1885 String packageName) {
1886 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1887 checkResolutionLevelIsSufficientForProviderUse(
1888 allowedResolutionLevel,
1889 LocationManager.GPS_PROVIDER);
1890
David Christieb870dbf2015-06-22 12:42:53 -07001891 int pid = Binder.getCallingPid();
destradaaea8a8a62014-06-23 18:19:03 -07001892 int uid = Binder.getCallingUid();
1893 long identity = Binder.clearCallingIdentity();
1894 boolean hasLocationAccess;
1895 try {
David Christieb870dbf2015-06-22 12:42:53 -07001896 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
destradaaea8a8a62014-06-23 18:19:03 -07001897 } finally {
1898 Binder.restoreCallingIdentity(identity);
1899 }
1900
Wei Liu5241a4c2015-05-11 14:00:36 -07001901 if (!hasLocationAccess || mGpsMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07001902 return false;
1903 }
destradaaea8a8a62014-06-23 18:19:03 -07001904 return mGpsMeasurementsProvider.addListener(listener);
1905 }
1906
1907 @Override
destradaa6568d702014-10-27 12:47:41 -07001908 public void removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
Wei Liu5241a4c2015-05-11 14:00:36 -07001909 if (mGpsMeasurementsProvider != null) {
1910 mGpsMeasurementsProvider.removeListener(listener);
1911 }
destradaaea8a8a62014-06-23 18:19:03 -07001912 }
1913
1914 @Override
destradaa4b3e3932014-07-21 18:01:47 -07001915 public boolean addGpsNavigationMessageListener(
1916 IGpsNavigationMessageListener listener,
1917 String packageName) {
1918 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1919 checkResolutionLevelIsSufficientForProviderUse(
1920 allowedResolutionLevel,
1921 LocationManager.GPS_PROVIDER);
1922
David Christieb870dbf2015-06-22 12:42:53 -07001923 int pid = Binder.getCallingPid();
destradaa4b3e3932014-07-21 18:01:47 -07001924 int uid = Binder.getCallingUid();
1925 long identity = Binder.clearCallingIdentity();
1926 boolean hasLocationAccess;
1927 try {
David Christieb870dbf2015-06-22 12:42:53 -07001928 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
destradaa4b3e3932014-07-21 18:01:47 -07001929 } finally {
1930 Binder.restoreCallingIdentity(identity);
1931 }
1932
Wei Liu5241a4c2015-05-11 14:00:36 -07001933 if (!hasLocationAccess || mGpsNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07001934 return false;
1935 }
1936 return mGpsNavigationMessageProvider.addListener(listener);
1937 }
1938
1939 @Override
destradaa6568d702014-10-27 12:47:41 -07001940 public void removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
Wei Liu5241a4c2015-05-11 14:00:36 -07001941 if (mGpsNavigationMessageProvider != null) {
1942 mGpsNavigationMessageProvider.removeListener(listener);
1943 }
destradaa4b3e3932014-07-21 18:01:47 -07001944 }
1945
1946 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001948 if (provider == null) {
1949 // throw NullPointerException to remain compatible with previous implementation
1950 throw new NullPointerException();
1951 }
Victoria Lease37425c32012-10-16 16:08:48 -07001952 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1953 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001956 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 != PackageManager.PERMISSION_GRANTED)) {
1958 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1959 }
1960
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001961 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001962 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001963 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001964
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001965 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 }
1967 }
1968
Nick Pellye0fd6932012-07-11 10:26:13 -07001969 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001970 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001971 if (Binder.getCallingUid() != Process.myUid()) {
1972 throw new SecurityException(
1973 "calling sendNiResponse from outside of the system is not allowed");
1974 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001975 try {
1976 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001977 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001978 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001979 return false;
1980 }
1981 }
1982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001984 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001985 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 * accessed by the caller
1987 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001988 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001989 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001990 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08001991 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07001992 }
1993
Victoria Lease37425c32012-10-16 16:08:48 -07001994 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1995 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001997 LocationProviderInterface p;
1998 synchronized (mLock) {
1999 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
2001
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002002 if (p == null) return null;
2003 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 }
2005
Jason Monkb71218a2015-06-17 14:44:39 -04002006 /**
2007 * @return null if the provider does not exist
2008 * @throws SecurityException if the provider is not allowed to be
2009 * accessed by the caller
2010 */
2011 @Override
2012 public String getNetworkProviderPackage() {
2013 LocationProviderInterface p;
2014 synchronized (mLock) {
2015 if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2016 return null;
2017 }
2018 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2019 }
2020
2021 if (p instanceof LocationProviderProxy) {
2022 return ((LocationProviderProxy) p).getConnectedPackageName();
2023 }
2024 return null;
2025 }
2026
Nick Pellye0fd6932012-07-11 10:26:13 -07002027 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 public boolean isProviderEnabled(String provider) {
Tom O'Neilld5759432013-09-11 11:03:03 -07002029 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2030 // so we discourage its use
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002031 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2032
Victoria Lease09eeaec2013-02-05 11:34:13 -08002033 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07002034 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002035 try {
2036 synchronized (mLock) {
2037 LocationProviderInterface p = mProvidersByName.get(provider);
2038 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002039
Victoria Lease09eeaec2013-02-05 11:34:13 -08002040 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07002041 }
2042 } finally {
2043 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002044 }
2045 }
2046
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002047 /**
2048 * Returns "true" if the UID belongs to a bound location provider.
2049 *
2050 * @param uid the uid
2051 * @return true if uid belongs to a bound location provider
2052 */
2053 private boolean isUidALocationProvider(int uid) {
2054 if (uid == Process.SYSTEM_UID) {
2055 return true;
2056 }
2057 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002058 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002059 }
2060 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002061 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002062 }
2063 return false;
2064 }
2065
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002066 private void checkCallerIsProvider() {
2067 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2068 == PackageManager.PERMISSION_GRANTED) {
2069 return;
2070 }
2071
2072 // Previously we only used the INSTALL_LOCATION_PROVIDER
2073 // check. But that is system or signature
2074 // protection level which is not flexible enough for
2075 // providers installed oustide the system image. So
2076 // also allow providers with a UID matching the
2077 // currently bound package name
2078
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002079 if (isUidALocationProvider(Binder.getCallingUid())) {
2080 return;
2081 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002082
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002083 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2084 "or UID of a currently bound location provider");
2085 }
2086
David Christie1f141c12014-05-14 15:11:15 -07002087 /**
2088 * Returns true if the given package belongs to the given uid.
2089 */
2090 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002091 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002092 return false;
2093 }
David Christie1f141c12014-05-14 15:11:15 -07002094 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2095 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002096 return false;
2097 }
David Christie1f141c12014-05-14 15:11:15 -07002098 for (String name : packageNames) {
2099 if (packageName.equals(name)) {
2100 return true;
2101 }
2102 }
2103 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 }
2105
Nick Pellye0fd6932012-07-11 10:26:13 -07002106 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002107 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002108 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002109
Nick Pelly2eeeec22012-07-18 13:13:37 -07002110 if (!location.isComplete()) {
2111 Log.w(TAG, "Dropping incomplete location: " + location);
2112 return;
2113 }
2114
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002115 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2116 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002117 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002118 mLocationHandler.sendMessageAtFrontOfQueue(m);
2119 }
2120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002121
Laurent Tu75defb62012-11-01 16:21:52 -07002122 private static boolean shouldBroadcastSafe(
2123 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002124 // Always broadcast the first update
2125 if (lastLoc == null) {
2126 return true;
2127 }
2128
Nick Pellyf1be6862012-05-15 10:53:42 -07002129 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002130 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002131 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2132 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002133 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002134 return false;
2135 }
2136
2137 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002138 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002139 if (minDistance > 0.0) {
2140 if (loc.distanceTo(lastLoc) <= minDistance) {
2141 return false;
2142 }
2143 }
2144
Laurent Tu75defb62012-11-01 16:21:52 -07002145 // Check whether sufficient number of udpates is left
2146 if (record.mRequest.getNumUpdates() <= 0) {
2147 return false;
2148 }
2149
2150 // Check whether the expiry date has passed
2151 if (record.mRequest.getExpireAt() < now) {
2152 return false;
2153 }
2154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155 return true;
2156 }
2157
Mike Lockwooda4903f22010-02-17 06:42:23 -05002158 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002159 if (D) Log.d(TAG, "incoming location: " + location);
2160
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002161 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002162 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163
Laurent Tu60ec50a2012-10-04 17:00:10 -07002164 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002165 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002166 if (p == null) return;
2167
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002168 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07002169 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2170 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002171 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002172 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002173 lastLocation = new Location(provider);
2174 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07002175 } else {
2176 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2177 if (noGPSLocation == null && lastNoGPSLocation != null) {
2178 // New location has no no-GPS location: adopt last no-GPS location. This is set
2179 // directly into location because we do not want to notify COARSE clients.
2180 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2181 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07002182 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002183 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184
David Christie1b9b7b12013-04-15 15:31:11 -07002185 // Update last known coarse interval location if enough time has passed.
2186 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2187 if (lastLocationCoarseInterval == null) {
2188 lastLocationCoarseInterval = new Location(location);
2189 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2190 }
2191 long timeDiffNanos = location.getElapsedRealtimeNanos()
2192 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2193 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2194 lastLocationCoarseInterval.set(location);
2195 }
2196 // Don't ever return a coarse location that is more recent than the allowed update
2197 // interval (i.e. don't allow an app to keep registering and unregistering for
2198 // location updates to overcome the minimum interval).
2199 noGPSLocation =
2200 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2201
Laurent Tu60ec50a2012-10-04 17:00:10 -07002202 // Skip if there are no UpdateRecords for this provider.
2203 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2204 if (records == null || records.size() == 0) return;
2205
Victoria Lease09016ab2012-09-16 12:33:15 -07002206 // Fetch coarse location
2207 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002208 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002209 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2210 }
2211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212 // Fetch latest status update time
2213 long newStatusUpdateTime = p.getStatusUpdateTime();
2214
David Christie2ff96af2014-01-30 16:09:37 -08002215 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 Bundle extras = new Bundle();
2217 int status = p.getStatus(extras);
2218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002220 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002223 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002225 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002226
Victoria Lease269518e2012-10-29 08:25:39 -07002227 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Amith Yamasanib27528d2014-06-05 15:02:10 -07002228 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002229 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002230 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002231 " (current user: " + mCurrentUserId + ", app: " +
2232 receiver.mPackageName + ")");
2233 }
2234 continue;
2235 }
2236
Nick Pelly4035f5a2012-08-17 14:43:49 -07002237 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2238 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2239 receiver.mPackageName);
2240 continue;
2241 }
2242
David Christieb870dbf2015-06-22 12:42:53 -07002243 if (!reportLocationAccessNoThrow(receiver.mPid, receiver.mUid, receiver.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002244 receiver.mAllowedResolutionLevel)) {
2245 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2246 receiver.mPackageName);
2247 continue;
2248 }
2249
Victoria Lease09016ab2012-09-16 12:33:15 -07002250 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07002251 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2252 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002253 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002254 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002255 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002256 if (notifyLocation != null) {
2257 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002258 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002259 if (lastLoc == null) {
2260 lastLoc = new Location(notifyLocation);
2261 r.mLastFixBroadcast = lastLoc;
2262 } else {
2263 lastLoc.set(notifyLocation);
2264 }
2265 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2266 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2267 receiverDead = true;
2268 }
Laurent Tu75defb62012-11-01 16:21:52 -07002269 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002270 }
2271 }
2272
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002273 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002274 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002275 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002276
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002277 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002278 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002279 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08002280 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07002281 }
2282 }
2283
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002284 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07002285 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002286 if (deadUpdateRecords == null) {
2287 deadUpdateRecords = new ArrayList<UpdateRecord>();
2288 }
2289 deadUpdateRecords.add(r);
2290 }
2291 // track dead receivers
2292 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002293 if (deadReceivers == null) {
2294 deadReceivers = new ArrayList<Receiver>();
2295 }
2296 if (!deadReceivers.contains(receiver)) {
2297 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002298 }
2299 }
2300 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002301
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002302 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002303 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002304 for (Receiver receiver : deadReceivers) {
2305 removeUpdatesLocked(receiver);
2306 }
2307 }
2308 if (deadUpdateRecords != null) {
2309 for (UpdateRecord r : deadUpdateRecords) {
2310 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002311 }
Victoria Lease8b38b292012-12-04 15:04:43 -08002312 applyRequirementsLocked(provider);
2313 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002314 }
2315
2316 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08002317 public LocationWorkerHandler(Looper looper) {
2318 super(looper, null, true);
2319 }
2320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002321 @Override
2322 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002323 switch (msg.what) {
2324 case MSG_LOCATION_CHANGED:
2325 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2326 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002327 }
2328 }
2329 }
2330
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002331 private boolean isMockProvider(String provider) {
2332 synchronized (mLock) {
2333 return mMockProviders.containsKey(provider);
2334 }
2335 }
2336
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002337 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002338 // create a working copy of the incoming Location so that the service can modify it without
2339 // disturbing the caller's copy
2340 Location myLocation = new Location(location);
2341 String provider = myLocation.getProvider();
2342
2343 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2344 // bit if location did not come from a mock provider because passive/fused providers can
2345 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2346 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2347 myLocation.setIsFromMockProvider(true);
2348 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08002349
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002350 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08002351 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2352 if (!passive) {
2353 // notify passive provider of the new location
2354 mPassiveProvider.updateLocation(myLocation);
2355 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002356 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002358 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002359 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002360
Mike Lockwoode97ae402010-09-29 15:23:46 -04002361 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2362 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002363 public void onPackageDisappeared(String packageName, int reason) {
2364 // remove all receivers associated with this package name
2365 synchronized (mLock) {
2366 ArrayList<Receiver> deadReceivers = null;
2367
2368 for (Receiver receiver : mReceivers.values()) {
2369 if (receiver.mPackageName.equals(packageName)) {
2370 if (deadReceivers == null) {
2371 deadReceivers = new ArrayList<Receiver>();
2372 }
2373 deadReceivers.add(receiver);
2374 }
2375 }
2376
2377 // perform removal outside of mReceivers loop
2378 if (deadReceivers != null) {
2379 for (Receiver receiver : deadReceivers) {
2380 removeUpdatesLocked(receiver);
2381 }
2382 }
2383 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002384 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002385 };
2386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002387 // Geocoder
2388
Nick Pellye0fd6932012-07-11 10:26:13 -07002389 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002390 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002391 return mGeocodeProvider != null;
2392 }
2393
Nick Pellye0fd6932012-07-11 10:26:13 -07002394 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002395 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002396 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002397 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002398 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2399 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002400 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002401 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002402 }
2403
Mike Lockwooda55c3212009-04-15 11:10:11 -04002404
Nick Pellye0fd6932012-07-11 10:26:13 -07002405 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002406 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002407 double lowerLeftLatitude, double lowerLeftLongitude,
2408 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002409 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002410
2411 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002412 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2413 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2414 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002415 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002416 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002417 }
2418
2419 // Mock Providers
2420
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002421 private boolean canCallerAccessMockLocation(String opPackageName) {
2422 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
2423 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002424 }
2425
Nick Pellye0fd6932012-07-11 10:26:13 -07002426 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002427 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
2428 if (!canCallerAccessMockLocation(opPackageName)) {
2429 return;
2430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002431
Mike Lockwooda4903f22010-02-17 06:42:23 -05002432 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2433 throw new IllegalArgumentException("Cannot mock the passive location provider");
2434 }
2435
Mike Lockwood86328a92009-10-23 08:38:25 -04002436 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002437 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002438 // remove the real provider if we are replacing GPS or network provider
2439 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002440 || LocationManager.NETWORK_PROVIDER.equals(name)
2441 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002442 LocationProviderInterface p = mProvidersByName.get(name);
2443 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002444 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002445 }
2446 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002447 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002448 updateProvidersLocked();
2449 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002450 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002451 }
2452
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002453 private void addTestProviderLocked(String name, ProviderProperties properties) {
2454 if (mProvidersByName.get(name) != null) {
2455 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2456 }
2457 MockProvider provider = new MockProvider(name, this, properties);
2458 addProviderLocked(provider);
2459 mMockProviders.put(name, provider);
2460 mLastLocation.put(name, null);
2461 mLastLocationCoarseInterval.put(name, null);
2462 }
2463
Nick Pellye0fd6932012-07-11 10:26:13 -07002464 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002465 public void removeTestProvider(String provider, String opPackageName) {
2466 if (!canCallerAccessMockLocation(opPackageName)) {
2467 return;
2468 }
2469
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002470 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002471
2472 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08002473 // we don't leave anything dangling.
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002474 clearTestProviderEnabled(provider, opPackageName);
2475 clearTestProviderLocation(provider, opPackageName);
2476 clearTestProviderStatus(provider, opPackageName);
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002477
You Kima6d0b6f2012-10-28 03:58:44 +09002478 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002479 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002480 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2481 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002482 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002483 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002484
2485 // reinstate real provider if available
2486 LocationProviderInterface realProvider = mRealProviders.get(provider);
2487 if (realProvider != null) {
2488 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002489 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002490 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002491 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002492 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002493 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002494 }
2495 }
2496
Nick Pellye0fd6932012-07-11 10:26:13 -07002497 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002498 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
2499 if (!canCallerAccessMockLocation(opPackageName)) {
2500 return;
2501 }
2502
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002503 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002504 MockProvider mockProvider = mMockProviders.get(provider);
2505 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002506 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2507 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002508 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2509 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002510 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002511 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002512 }
2513 }
2514
Nick Pellye0fd6932012-07-11 10:26:13 -07002515 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002516 public void clearTestProviderLocation(String provider, String opPackageName) {
2517 if (!canCallerAccessMockLocation(opPackageName)) {
2518 return;
2519 }
2520
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002521 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002522 MockProvider mockProvider = mMockProviders.get(provider);
2523 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002524 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2525 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002526 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002527 }
2528 }
2529
Nick Pellye0fd6932012-07-11 10:26:13 -07002530 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002531 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
2532 if (!canCallerAccessMockLocation(opPackageName)) {
2533 return;
2534 }
2535
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002536 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002537 MockProvider mockProvider = mMockProviders.get(provider);
2538 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002539 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2540 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002541 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002542 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002543 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002544 mEnabledProviders.add(provider);
2545 mDisabledProviders.remove(provider);
2546 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002547 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 mEnabledProviders.remove(provider);
2549 mDisabledProviders.add(provider);
2550 }
2551 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002552 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002553 }
2554 }
2555
Nick Pellye0fd6932012-07-11 10:26:13 -07002556 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002557 public void clearTestProviderEnabled(String provider, String opPackageName) {
2558 if (!canCallerAccessMockLocation(opPackageName)) {
2559 return;
2560 }
2561
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002562 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002563 MockProvider mockProvider = mMockProviders.get(provider);
2564 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002565 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2566 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002567 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002568 mEnabledProviders.remove(provider);
2569 mDisabledProviders.remove(provider);
2570 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002571 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002572 }
2573 }
2574
Nick Pellye0fd6932012-07-11 10:26:13 -07002575 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002576 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
2577 String opPackageName) {
2578 if (!canCallerAccessMockLocation(opPackageName)) {
2579 return;
2580 }
2581
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002582 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002583 MockProvider mockProvider = mMockProviders.get(provider);
2584 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002585 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2586 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002587 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002588 }
2589 }
2590
Nick Pellye0fd6932012-07-11 10:26:13 -07002591 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002592 public void clearTestProviderStatus(String provider, String opPackageName) {
2593 if (!canCallerAccessMockLocation(opPackageName)) {
2594 return;
2595 }
2596
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002597 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002598 MockProvider mockProvider = mMockProviders.get(provider);
2599 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002600 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2601 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002602 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002603 }
2604 }
2605
2606 private void log(String log) {
2607 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002608 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002609 }
2610 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002611
2612 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002613 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2614 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2615 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002616 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002617 + Binder.getCallingPid()
2618 + ", uid=" + Binder.getCallingUid());
2619 return;
2620 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002621
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002622 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002623 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002624 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002625 for (Receiver receiver : mReceivers.values()) {
2626 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002627 }
David Christie2ff96af2014-01-30 16:09:37 -08002628 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002629 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2630 pw.println(" " + entry.getKey() + ":");
2631 for (UpdateRecord record : entry.getValue()) {
2632 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633 }
2634 }
David Christie2ff96af2014-01-30 16:09:37 -08002635 pw.println(" Historical Records by Provider:");
2636 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2637 : mRequestStatistics.statistics.entrySet()) {
2638 PackageProviderKey key = entry.getKey();
2639 PackageStatistics stats = entry.getValue();
2640 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
2641 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002642 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002643 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2644 String provider = entry.getKey();
2645 Location location = entry.getValue();
2646 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002648
David Christie1b9b7b12013-04-15 15:31:11 -07002649 pw.println(" Last Known Locations Coarse Intervals:");
2650 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2651 String provider = entry.getKey();
2652 Location location = entry.getValue();
2653 pw.println(" " + provider + ": " + location);
2654 }
2655
Nick Pellye0fd6932012-07-11 10:26:13 -07002656 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 if (mEnabledProviders.size() > 0) {
2659 pw.println(" Enabled Providers:");
2660 for (String i : mEnabledProviders) {
2661 pw.println(" " + i);
2662 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002664 }
2665 if (mDisabledProviders.size() > 0) {
2666 pw.println(" Disabled Providers:");
2667 for (String i : mDisabledProviders) {
2668 pw.println(" " + i);
2669 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002670 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002671 pw.append(" ");
2672 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002673 if (mMockProviders.size() > 0) {
2674 pw.println(" Mock Providers:");
2675 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002676 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002677 }
2678 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002679
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002680 pw.append(" fudger: ");
2681 mLocationFudger.dump(fd, pw, args);
2682
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002683 if (args.length > 0 && "short".equals(args[0])) {
2684 return;
2685 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002686 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002687 pw.print(provider.getName() + " Internal State");
2688 if (provider instanceof LocationProviderProxy) {
2689 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2690 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002691 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002692 pw.println(":");
2693 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002695 }
2696 }
2697}