blob: 9405d8e05c5e7105c38279316d11c47965985076 [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
Xiaohui Chena4490622015-09-22 15:29:31 -0700214 private int mCurrentUserId = UserHandle.USER_SYSTEM;
215 private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
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);
destradaab9026982015-08-27 17:34:54 -0700310 intentFilter.addAction(Intent.ACTION_SHUTDOWN);
Victoria Lease38389b62012-09-30 11:44:22 -0700311
312 mContext.registerReceiverAsUser(new BroadcastReceiver() {
313 @Override
314 public void onReceive(Context context, Intent intent) {
315 String action = intent.getAction();
316 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
317 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700318 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
319 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
320 updateUserProfiles(mCurrentUserId);
destradaab9026982015-08-27 17:34:54 -0700321 } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
322 shutdownComponents();
Victoria Lease38389b62012-09-30 11:44:22 -0700323 }
324 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800325 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700326 }
327
Amith Yamasanib27528d2014-06-05 15:02:10 -0700328 /**
destradaab9026982015-08-27 17:34:54 -0700329 * Provides a way for components held by the {@link LocationManagerService} to clean-up
330 * gracefully on system's shutdown.
331 *
332 * NOTES:
333 * 1) Only provides a chance to clean-up on an opt-in basis. This guarantees back-compat
334 * support for components that do not wish to handle such event.
335 */
336 private void shutdownComponents() {
337 if(D) Log.d(TAG, "Shutting down components...");
338
339 LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
340 if (gpsProvider != null && gpsProvider.isEnabled()) {
341 gpsProvider.disable();
342 }
343
destradaa2e385072015-10-14 16:45:58 -0700344 // it is needed to check if FLP HW provider is supported before accessing the instance, this
345 // avoids an exception to be thrown by the singleton factory method
346 if (FlpHardwareProvider.isSupported()) {
347 FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
destradaab9026982015-08-27 17:34:54 -0700348 flpHardwareProvider.cleanup();
349 }
350 }
351
352 /**
Amith Yamasanib27528d2014-06-05 15:02:10 -0700353 * Makes a list of userids that are related to the current user. This is
354 * relevant when using managed profiles. Otherwise the list only contains
355 * the current user.
356 *
357 * @param currentUserId the current user, who might have an alter-ego.
358 */
359 void updateUserProfiles(int currentUserId) {
360 List<UserInfo> profiles = mUserManager.getProfiles(currentUserId);
361 synchronized (mLock) {
362 mCurrentUserProfiles = new int[profiles.size()];
363 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
364 mCurrentUserProfiles[i] = profiles.get(i).id;
365 }
366 }
367 }
368
369 /**
370 * Checks if the specified userId matches any of the current foreground
371 * users stored in mCurrentUserProfiles.
372 */
373 private boolean isCurrentProfile(int userId) {
374 synchronized (mLock) {
375 for (int i = 0; i < mCurrentUserProfiles.length; i++) {
376 if (mCurrentUserProfiles[i] == userId) {
377 return true;
378 }
379 }
380 return false;
381 }
382 }
383
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500384 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
385 PackageManager pm = mContext.getPackageManager();
386 String systemPackageName = mContext.getPackageName();
387 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
388
389 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
390 new Intent(FUSED_LOCATION_SERVICE_ACTION),
391 PackageManager.GET_META_DATA, mCurrentUserId);
392 for (ResolveInfo rInfo : rInfos) {
393 String packageName = rInfo.serviceInfo.packageName;
394
395 // Check that the signature is in the list of supported sigs. If it's not in
396 // this list the standard provider binding logic won't bind to it.
397 try {
398 PackageInfo pInfo;
399 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
400 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
401 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
402 ", but has wrong signature, ignoring");
403 continue;
404 }
405 } catch (NameNotFoundException e) {
406 Log.e(TAG, "missing package: " + packageName);
407 continue;
408 }
409
410 // Get the version info
411 if (rInfo.serviceInfo.metaData == null) {
412 Log.w(TAG, "Found fused provider without metadata: " + packageName);
413 continue;
414 }
415
416 int version = rInfo.serviceInfo.metaData.getInt(
417 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
418 if (version == 0) {
419 // This should be the fallback fused location provider.
420
421 // Make sure it's in the system partition.
422 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
423 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
424 continue;
425 }
426
427 // Check that the fallback is signed the same as the OS
428 // as a proxy for coreApp="true"
429 if (pm.checkSignatures(systemPackageName, packageName)
430 != PackageManager.SIGNATURE_MATCH) {
431 if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
432 + packageName);
433 continue;
434 }
435
436 // Found a valid fallback.
437 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
438 return;
439 } else {
440 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
441 }
442 }
443
444 throw new IllegalStateException("Unable to find a fused location provider that is in the "
445 + "system partition with version 0 and signed with the platform certificate. "
446 + "Such a package is needed to provide a default fused location provider in the "
447 + "event that no other fused location provider has been installed or is currently "
448 + "available. For example, coreOnly boot mode when decrypting the data "
449 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
450 }
451
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700452 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700453 // create a passive location provider, which is always enabled
454 PassiveProvider passiveProvider = new PassiveProvider(this);
455 addProviderLocked(passiveProvider);
456 mEnabledProviders.add(passiveProvider.getName());
457 mPassiveProvider = passiveProvider;
458
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700459 if (GpsLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700460 // Create a gps location provider
461 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
462 mLocationHandler.getLooper());
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700463 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
464 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
465 addProviderLocked(gpsProvider);
466 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
Wei Liu5241a4c2015-05-11 14:00:36 -0700467 mGpsMeasurementsProvider = gpsProvider.getGpsMeasurementsProvider();
468 mGpsNavigationMessageProvider = gpsProvider.getGpsNavigationMessageProvider();
469 mGpsGeofenceProxy = gpsProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700470 }
471
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700472 /*
473 Load package name(s) containing location provider support.
474 These packages can contain services implementing location providers:
475 Geocoder Provider, Network Location Provider, and
476 Fused Location Provider. They will each be searched for
477 service components implementing these providers.
478 The location framework also has support for installation
479 of new location providers at run-time. The new package does not
480 have to be explicitly listed here, however it must have a signature
481 that matches the signature of at least one package on this list.
482 */
483 Resources resources = mContext.getResources();
484 ArrayList<String> providerPackageNames = new ArrayList<String>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500485 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700486 com.android.internal.R.array.config_locationProviderPackageNames);
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500487 if (D) Log.d(TAG, "certificates for location providers pulled from: " +
488 Arrays.toString(pkgs));
489 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
490
491 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700492
493 // bind to network provider
494 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
495 mContext,
496 LocationManager.NETWORK_PROVIDER,
497 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700498 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
499 com.android.internal.R.string.config_networkLocationProviderPackageName,
500 com.android.internal.R.array.config_locationProviderPackageNames,
501 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700502 if (networkProvider != null) {
503 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
504 mProxyProviders.add(networkProvider);
505 addProviderLocked(networkProvider);
506 } else {
507 Slog.w(TAG, "no network location provider found");
508 }
509
510 // bind to fused provider
511 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
512 mContext,
513 LocationManager.FUSED_PROVIDER,
514 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700515 com.android.internal.R.bool.config_enableFusedLocationOverlay,
516 com.android.internal.R.string.config_fusedLocationProviderPackageName,
517 com.android.internal.R.array.config_locationProviderPackageNames,
518 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700519 if (fusedLocationProvider != null) {
520 addProviderLocked(fusedLocationProvider);
521 mProxyProviders.add(fusedLocationProvider);
522 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700523 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700524 } else {
525 Slog.e(TAG, "no fused location provider found",
526 new IllegalStateException("Location service needs a fused location provider"));
527 }
528
529 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700530 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
531 com.android.internal.R.bool.config_enableGeocoderOverlay,
532 com.android.internal.R.string.config_geocoderProviderPackageName,
533 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800534 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700535 if (mGeocodeProvider == null) {
536 Slog.e(TAG, "no geocoder provider found");
537 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700538
destradaaa4fa3b52014-07-09 10:46:39 -0700539 // bind to fused hardware provider if supported
destradaabeea4422014-07-30 18:17:21 -0700540 // in devices without support, requesting an instance of FlpHardwareProvider will raise an
541 // exception, so make sure we only do that when supported
542 FlpHardwareProvider flpHardwareProvider;
destradaa5ce66d82014-05-28 18:24:08 -0700543 if (FlpHardwareProvider.isSupported()) {
destradaabeea4422014-07-30 18:17:21 -0700544 flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
destradaaf9a274c2014-07-25 15:11:56 -0700545 FusedProxy fusedProxy = FusedProxy.createAndBind(
546 mContext,
547 mLocationHandler,
548 flpHardwareProvider.getLocationHardware(),
549 com.android.internal.R.bool.config_enableHardwareFlpOverlay,
550 com.android.internal.R.string.config_hardwareFlpPackageName,
551 com.android.internal.R.array.config_locationProviderPackageNames);
552 if (fusedProxy == null) {
553 Slog.e(TAG, "Unable to bind FusedProxy.");
554 }
destradaacfbdcd22014-04-30 11:29:11 -0700555 } else {
destradaabeea4422014-07-30 18:17:21 -0700556 flpHardwareProvider = null;
destradaaf9a274c2014-07-25 15:11:56 -0700557 Slog.e(TAG, "FLP HAL not supported");
558 }
559
560 // bind to geofence provider
561 GeofenceProxy provider = GeofenceProxy.createAndBind(
562 mContext,com.android.internal.R.bool.config_enableGeofenceOverlay,
563 com.android.internal.R.string.config_geofenceProviderPackageName,
564 com.android.internal.R.array.config_locationProviderPackageNames,
565 mLocationHandler,
Wei Liu5241a4c2015-05-11 14:00:36 -0700566 mGpsGeofenceProxy,
destradaabeea4422014-07-30 18:17:21 -0700567 flpHardwareProvider != null ? flpHardwareProvider.getGeofenceHardware() : null);
destradaaf9a274c2014-07-25 15:11:56 -0700568 if (provider == null) {
569 Slog.e(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700570 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900571
destradaa6e2fe752015-06-23 17:25:53 -0700572 // bind to hardware activity recognition
573 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
574 ActivityRecognitionHardware activityRecognitionHardware = null;
575 if (activityRecognitionHardwareIsSupported) {
576 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700577 } else {
578 Slog.e(TAG, "Hardware Activity-Recognition not supported.");
579 }
destradaa6e2fe752015-06-23 17:25:53 -0700580 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
581 mContext,
582 mLocationHandler,
583 activityRecognitionHardwareIsSupported,
584 activityRecognitionHardware,
585 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
586 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
587 com.android.internal.R.array.config_locationProviderPackageNames);
588 if (proxy == null) {
589 Slog.e(TAG, "Unable to bind ActivityRecognitionProxy.");
590 }
destradaaa4fa3b52014-07-09 10:46:39 -0700591
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900592 String[] testProviderStrings = resources.getStringArray(
593 com.android.internal.R.array.config_testLocationProviders);
594 for (String testProviderString : testProviderStrings) {
595 String fragments[] = testProviderString.split(",");
596 String name = fragments[0].trim();
597 if (mProvidersByName.get(name) != null) {
598 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
599 }
600 ProviderProperties properties = new ProviderProperties(
601 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
602 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
603 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
604 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
605 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
606 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
607 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
608 Integer.parseInt(fragments[8]) /* powerRequirement */,
609 Integer.parseInt(fragments[9]) /* accuracy */);
610 addTestProviderLocked(name, properties);
611 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700612 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700615 * Called when the device's active user changes.
616 * @param userId the new active user's UserId
617 */
618 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800619 if (mCurrentUserId == userId) {
620 return;
621 }
Victoria Lease83762d22012-10-03 13:51:17 -0700622 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800623 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700624 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700625 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700626 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700627 for (LocationProviderInterface p : mProviders) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700628 updateProviderListenersLocked(p.getName(), false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700629 }
Victoria Lease38389b62012-09-30 11:44:22 -0700630 mCurrentUserId = userId;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700631 updateUserProfiles(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700632 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700633 }
634 }
635
636 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
638 * location updates.
639 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700640 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700641 final int mUid; // uid of receiver
642 final int mPid; // pid of receiver
643 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700644 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 final ILocationListener mListener;
647 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700648 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700649 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700651
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400652 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700653
David Christie0b837452013-07-29 16:02:13 -0700654 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700655 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700656 // True if app ops has started monitoring this receiver for high power (gps) locations.
657 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700658 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700659 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700662 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700665 if (listener != null) {
666 mKey = listener.asBinder();
667 } else {
668 mKey = intent;
669 }
Victoria Lease37425c32012-10-16 16:08:48 -0700670 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700671 mUid = uid;
672 mPid = pid;
673 mPackageName = packageName;
David Christie82edc9b2013-07-19 11:31:42 -0700674 if (workSource != null && workSource.size() <= 0) {
675 workSource = null;
676 }
677 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700678 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700679
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700680 updateMonitoring(true);
681
Victoria Lease0aa28602013-05-29 15:28:26 -0700682 // construct/configure wakelock
683 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700684 if (workSource == null) {
685 workSource = new WorkSource(mUid, mPackageName);
686 }
687 mWakeLock.setWorkSource(workSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 }
689
690 @Override
691 public boolean equals(Object otherObj) {
692 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700693 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 }
695 return false;
696 }
697
698 @Override
699 public int hashCode() {
700 return mKey.hashCode();
701 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 @Override
704 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700705 StringBuilder s = new StringBuilder();
706 s.append("Reciever[");
707 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700709 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700711 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700713 for (String p : mUpdateRecords.keySet()) {
714 s.append(" ").append(mUpdateRecords.get(p).toString());
715 }
716 s.append("]");
717 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 }
719
David Christie15b31912013-08-13 15:54:32 -0700720 /**
721 * Update AppOp monitoring for this receiver.
722 *
723 * @param allow If true receiver is currently active, if false it's been removed.
724 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700725 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700726 if (mHideFromAppOps) {
727 return;
728 }
729
David Christie15b31912013-08-13 15:54:32 -0700730 boolean requestingLocation = false;
731 boolean requestingHighPowerLocation = false;
732 if (allow) {
733 // See if receiver has any enabled update records. Also note if any update records
734 // are high power (has a high power provider with an interval under a threshold).
735 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
736 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
737 requestingLocation = true;
738 LocationProviderInterface locationProvider
David Christie2ff96af2014-01-30 16:09:37 -0800739 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -0700740 ProviderProperties properties = locationProvider != null
741 ? locationProvider.getProperties() : null;
742 if (properties != null
743 && properties.mPowerRequirement == Criteria.POWER_HIGH
744 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
745 requestingHighPowerLocation = true;
746 break;
747 }
748 }
749 }
750 }
751
David Christie0b837452013-07-29 16:02:13 -0700752 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700753 mOpMonitoring = updateMonitoring(
754 requestingLocation,
755 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700756 AppOpsManager.OP_MONITOR_LOCATION);
757
758 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700759 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700760 mOpHighPowerMonitoring = updateMonitoring(
761 requestingHighPowerLocation,
762 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700763 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700764 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700765 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700766 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
767 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
768 }
David Christie0b837452013-07-29 16:02:13 -0700769 }
770
771 /**
772 * Update AppOps monitoring for a single location request and op type.
773 *
774 * @param allowMonitoring True if monitoring is allowed for this request/op.
775 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
776 * @param op AppOps code for the op to update.
777 * @return True if monitoring is on for this request/op after updating.
778 */
779 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
780 int op) {
781 if (!currentlyMonitoring) {
782 if (allowMonitoring) {
783 return mAppOps.startOpNoThrow(op, mUid, mPackageName)
784 == AppOpsManager.MODE_ALLOWED;
785 }
786 } else {
787 if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
788 != AppOpsManager.MODE_ALLOWED) {
789 mAppOps.finishOp(op, mUid, mPackageName);
790 return false;
791 }
792 }
793
794 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700795 }
796
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 public boolean isListener() {
798 return mListener != null;
799 }
800
801 public boolean isPendingIntent() {
802 return mPendingIntent != null;
803 }
804
805 public ILocationListener getListener() {
806 if (mListener != null) {
807 return mListener;
808 }
809 throw new IllegalStateException("Request for non-existent listener");
810 }
811
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
813 if (mListener != null) {
814 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700815 synchronized (this) {
816 // synchronize to ensure incrementPendingBroadcastsLocked()
817 // is called before decrementPendingBroadcasts()
818 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700819 // call this after broadcasting so we do not increment
820 // if we throw an exeption.
821 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 } catch (RemoteException e) {
824 return false;
825 }
826 } else {
827 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800828 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
830 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700831 synchronized (this) {
832 // synchronize to ensure incrementPendingBroadcastsLocked()
833 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700834 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700835 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700836 // call this after broadcasting so we do not increment
837 // if we throw an exeption.
838 incrementPendingBroadcastsLocked();
839 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 } catch (PendingIntent.CanceledException e) {
841 return false;
842 }
843 }
844 return true;
845 }
846
847 public boolean callLocationChangedLocked(Location location) {
848 if (mListener != null) {
849 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700850 synchronized (this) {
851 // synchronize to ensure incrementPendingBroadcastsLocked()
852 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -0800853 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -0700854 // call this after broadcasting so we do not increment
855 // if we throw an exeption.
856 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 } catch (RemoteException e) {
859 return false;
860 }
861 } else {
862 Intent locationChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800863 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700865 synchronized (this) {
866 // synchronize to ensure incrementPendingBroadcastsLocked()
867 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700868 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700869 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700870 // call this after broadcasting so we do not increment
871 // if we throw an exeption.
872 incrementPendingBroadcastsLocked();
873 }
874 } catch (PendingIntent.CanceledException e) {
875 return false;
876 }
877 }
878 return true;
879 }
880
881 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -0700882 // First update AppOp monitoring.
883 // An app may get/lose location access as providers are enabled/disabled.
884 updateMonitoring(true);
885
Mike Lockwood48f17512009-04-23 09:12:08 -0700886 if (mListener != null) {
887 try {
888 synchronized (this) {
889 // synchronize to ensure incrementPendingBroadcastsLocked()
890 // is called before decrementPendingBroadcasts()
891 if (enabled) {
892 mListener.onProviderEnabled(provider);
893 } else {
894 mListener.onProviderDisabled(provider);
895 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700896 // call this after broadcasting so we do not increment
897 // if we throw an exeption.
898 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700899 }
900 } catch (RemoteException e) {
901 return false;
902 }
903 } else {
904 Intent providerIntent = new Intent();
905 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
906 try {
907 synchronized (this) {
908 // synchronize to ensure incrementPendingBroadcastsLocked()
909 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700910 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700911 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700912 // call this after broadcasting so we do not increment
913 // if we throw an exeption.
914 incrementPendingBroadcastsLocked();
915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 } catch (PendingIntent.CanceledException e) {
917 return false;
918 }
919 }
920 return true;
921 }
922
Nick Pellyf1be6862012-05-15 10:53:42 -0700923 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700925 if (D) Log.d(TAG, "Location listener died");
926
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400927 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 removeUpdatesLocked(this);
929 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700930 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700931 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700932 }
933 }
934
Nick Pellye0fd6932012-07-11 10:26:13 -0700935 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700936 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
937 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400938 synchronized (this) {
939 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700940 }
941 }
942
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400943 // this must be called while synchronized by caller in a synchronized block
944 // containing the sending of the broadcaset
945 private void incrementPendingBroadcastsLocked() {
946 if (mPendingBroadcasts++ == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700947 mWakeLock.acquire();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400948 }
949 }
950
951 private void decrementPendingBroadcastsLocked() {
952 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -0700953 if (mWakeLock.isHeld()) {
954 mWakeLock.release();
955 }
956 }
957 }
958
959 public void clearPendingBroadcastsLocked() {
960 if (mPendingBroadcasts > 0) {
961 mPendingBroadcasts = 0;
962 if (mWakeLock.isHeld()) {
963 mWakeLock.release();
964 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700965 }
966 }
967 }
968
Nick Pellye0fd6932012-07-11 10:26:13 -0700969 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700970 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700971 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -0400972 //the receiver list if it is not found. If it is not found then the
973 //LocationListener was removed when it had a pending broadcast and should
974 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700975 synchronized (mLock) {
976 IBinder binder = listener.asBinder();
977 Receiver receiver = mReceivers.get(binder);
978 if (receiver != null) {
979 synchronized (receiver) {
980 // so wakelock calls will succeed
981 long identity = Binder.clearCallingIdentity();
982 receiver.decrementPendingBroadcastsLocked();
983 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -0800984 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -0700985 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 }
987 }
988
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700989 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400990 mProviders.add(provider);
991 mProvidersByName.put(provider.getName(), provider);
992 }
993
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700994 private void removeProviderLocked(LocationProviderInterface provider) {
995 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400996 mProviders.remove(provider);
997 mProvidersByName.remove(provider.getName());
998 }
999
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001000 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001001 * Returns "true" if access to the specified location provider is allowed by the current
1002 * user's settings. Access to all location providers is forbidden to non-location-provider
1003 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001004 *
1005 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001006 * @return
1007 */
Victoria Lease09eeaec2013-02-05 11:34:13 -08001008 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 if (mEnabledProviders.contains(provider)) {
1010 return true;
1011 }
1012 if (mDisabledProviders.contains(provider)) {
1013 return false;
1014 }
1015 // Use system settings
1016 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017
Victoria Leaseb711d572012-10-02 13:14:11 -07001018 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 }
1020
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001021 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001022 * Returns "true" if access to the specified location provider is allowed by the specified
1023 * user's settings. Access to all location providers is forbidden to non-location-provider
1024 * processes belonging to background users.
1025 *
1026 * @param provider the name of the location provider
1027 * @param uid the requestor's UID
1028 * @return
1029 */
1030 private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001031 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001032 return false;
1033 }
1034 return isAllowedByCurrentUserSettingsLocked(provider);
1035 }
1036
1037 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001038 * Returns the permission string associated with the specified resolution level.
1039 *
1040 * @param resolutionLevel the resolution level
1041 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001042 */
Victoria Lease37425c32012-10-16 16:08:48 -07001043 private String getResolutionPermission(int resolutionLevel) {
1044 switch (resolutionLevel) {
1045 case RESOLUTION_LEVEL_FINE:
1046 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1047 case RESOLUTION_LEVEL_COARSE:
1048 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1049 default:
1050 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001052 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001053
Victoria Leaseda479c52012-10-15 15:24:16 -07001054 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001055 * Returns the resolution level allowed to the given PID/UID pair.
1056 *
1057 * @param pid the PID
1058 * @param uid the UID
1059 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001060 */
Victoria Lease37425c32012-10-16 16:08:48 -07001061 private int getAllowedResolutionLevel(int pid, int uid) {
1062 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
1063 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1064 return RESOLUTION_LEVEL_FINE;
1065 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
1066 pid, uid) == PackageManager.PERMISSION_GRANTED) {
1067 return RESOLUTION_LEVEL_COARSE;
1068 } else {
1069 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001070 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001071 }
1072
1073 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001074 * Returns the resolution level allowed to the caller
1075 *
1076 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001077 */
Victoria Lease37425c32012-10-16 16:08:48 -07001078 private int getCallerAllowedResolutionLevel() {
1079 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1080 }
1081
1082 /**
1083 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1084 *
1085 * @param allowedResolutionLevel resolution level allowed to caller
1086 */
1087 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1088 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001089 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 }
1092
Victoria Lease37425c32012-10-16 16:08:48 -07001093 /**
1094 * Return the minimum resolution level required to use the specified location provider.
1095 *
1096 * @param provider the name of the location provider
1097 * @return minimum resolution level required for provider
1098 */
1099 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001100 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1101 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1102 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001103 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001104 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1105 LocationManager.FUSED_PROVIDER.equals(provider)) {
1106 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001107 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001108 } else {
1109 // mock providers
1110 LocationProviderInterface lp = mMockProviders.get(provider);
1111 if (lp != null) {
1112 ProviderProperties properties = lp.getProperties();
1113 if (properties != null) {
1114 if (properties.mRequiresSatellite) {
1115 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001116 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001117 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1118 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001119 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001120 }
1121 }
1122 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001123 }
Victoria Lease37425c32012-10-16 16:08:48 -07001124 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001125 }
1126
Victoria Lease37425c32012-10-16 16:08:48 -07001127 /**
1128 * Throw SecurityException if specified resolution level is insufficient to use the named
1129 * location provider.
1130 *
1131 * @param allowedResolutionLevel resolution level allowed to caller
1132 * @param providerName the name of the location provider
1133 */
1134 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1135 String providerName) {
1136 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1137 if (allowedResolutionLevel < requiredResolutionLevel) {
1138 switch (requiredResolutionLevel) {
1139 case RESOLUTION_LEVEL_FINE:
1140 throw new SecurityException("\"" + providerName + "\" location provider " +
1141 "requires ACCESS_FINE_LOCATION permission.");
1142 case RESOLUTION_LEVEL_COARSE:
1143 throw new SecurityException("\"" + providerName + "\" location provider " +
1144 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1145 default:
1146 throw new SecurityException("Insufficient permission for \"" + providerName +
1147 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001148 }
1149 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001150 }
1151
David Christie82edc9b2013-07-19 11:31:42 -07001152 /**
1153 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1154 * for battery).
1155 */
David Christie40e57822013-07-30 11:36:48 -07001156 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001157 mContext.enforceCallingOrSelfPermission(
1158 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1159 }
1160
David Christie40e57822013-07-30 11:36:48 -07001161 private void checkUpdateAppOpsAllowed() {
1162 mContext.enforceCallingOrSelfPermission(
1163 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1164 }
1165
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001166 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001167 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1168 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001169 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001170 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001171 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001172 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001173 }
1174 return -1;
1175 }
1176
David Christieb870dbf2015-06-22 12:42:53 -07001177 boolean reportLocationAccessNoThrow(
1178 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001179 int op = resolutionLevelToOp(allowedResolutionLevel);
1180 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001181 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1182 return false;
1183 }
1184 }
David Christieb870dbf2015-06-22 12:42:53 -07001185
1186 if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
1187 return false;
1188 }
1189
Dianne Hackborn35654b62013-01-14 17:38:02 -08001190 return true;
1191 }
1192
David Christieb870dbf2015-06-22 12:42:53 -07001193 boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001194 int op = resolutionLevelToOp(allowedResolutionLevel);
1195 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001196 if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1197 return false;
1198 }
1199 }
David Christieb870dbf2015-06-22 12:42:53 -07001200
1201 if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
1202 return false;
1203 }
1204
Dianne Hackborn35654b62013-01-14 17:38:02 -08001205 return true;
1206 }
1207
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001208 /**
1209 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -07001210 * fused, also including ones that are not permitted to
1211 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001212 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001213 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001215 ArrayList<String> out;
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)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001221 continue;
1222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 out.add(name);
1224 }
1225 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001226
1227 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 return out;
1229 }
1230
Mike Lockwood03ca2162010-04-01 08:10:09 -07001231 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001232 * Return all providers by name, that match criteria and are optionally
1233 * enabled.
1234 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001235 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236 @Override
1237 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001238 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001239 ArrayList<String> out;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001240 int uid = Binder.getCallingUid();;
Victoria Lease269518e2012-10-29 08:25:39 -07001241 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001242 try {
1243 synchronized (mLock) {
1244 out = new ArrayList<String>(mProviders.size());
1245 for (LocationProviderInterface provider : mProviders) {
1246 String name = provider.getName();
1247 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001248 continue;
1249 }
Victoria Lease37425c32012-10-16 16:08:48 -07001250 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001251 if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001252 continue;
1253 }
1254 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1255 name, provider.getProperties(), criteria)) {
1256 continue;
1257 }
1258 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001259 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001260 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001261 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001262 } finally {
1263 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001264 }
1265
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001266 if (D) Log.d(TAG, "getProviders()=" + out);
1267 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001268 }
1269
1270 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001271 * Return the name of the best provider given a Criteria object.
1272 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001273 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001274 * has been deprecated as well. So this method now uses
1275 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001276 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001277 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001278 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001279 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001280
1281 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001282 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001283 result = pickBest(providers);
1284 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1285 return result;
1286 }
1287 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001288 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001289 result = pickBest(providers);
1290 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1291 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001292 }
1293
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001294 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001295 return null;
1296 }
1297
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001298 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001299 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001300 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001301 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1302 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001303 } else {
1304 return providers.get(0);
1305 }
1306 }
1307
Nick Pellye0fd6932012-07-11 10:26:13 -07001308 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001309 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1310 LocationProviderInterface p = mProvidersByName.get(provider);
1311 if (p == null) {
1312 throw new IllegalArgumentException("provider=" + provider);
1313 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001314
1315 boolean result = LocationProvider.propertiesMeetCriteria(
1316 p.getName(), p.getProperties(), criteria);
1317 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1318 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001319 }
1320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001322 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001323 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001324 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 boolean isEnabled = p.isEnabled();
1326 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001327 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001329 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001330 // If any provider has been disabled, clear all last locations for all providers.
1331 // This is to be on the safe side in case a provider has location derived from
1332 // this disabled provider.
1333 mLastLocation.clear();
1334 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001335 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001337 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001338 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001340 }
1341 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001342 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1343 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001344 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1345 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 }
1347 }
1348
Amith Yamasanib27528d2014-06-05 15:02:10 -07001349 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 int listeners = 0;
1351
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001352 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001353 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354
1355 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001357 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1358 if (records != null) {
1359 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001360 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361 UpdateRecord record = records.get(i);
Amith Yamasanib27528d2014-06-05 15:02:10 -07001362 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001363 // Sends a notification message to the receiver
1364 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1365 if (deadReceivers == null) {
1366 deadReceivers = new ArrayList<Receiver>();
1367 }
1368 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001370 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 }
1373 }
1374
1375 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001376 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 removeUpdatesLocked(deadReceivers.get(i));
1378 }
1379 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 if (enabled) {
1382 p.enable();
1383 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001384 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 }
1386 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 }
1390
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001391 private void applyRequirementsLocked(String provider) {
1392 LocationProviderInterface p = mProvidersByName.get(provider);
1393 if (p == null) return;
1394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001396 WorkSource worksource = new WorkSource();
1397 ProviderRequest providerRequest = new ProviderRequest();
1398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001400 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001401 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001402 if (checkLocationAccess(
1403 record.mReceiver.mPid,
1404 record.mReceiver.mUid,
1405 record.mReceiver.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001406 record.mReceiver.mAllowedResolutionLevel)) {
1407 LocationRequest locationRequest = record.mRequest;
1408 providerRequest.locationRequests.add(locationRequest);
1409 if (locationRequest.getInterval() < providerRequest.interval) {
1410 providerRequest.reportLocation = true;
1411 providerRequest.interval = locationRequest.getInterval();
1412 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001413 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001414 }
1415 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001416
1417 if (providerRequest.reportLocation) {
1418 // calculate who to blame for power
1419 // This is somewhat arbitrary. We pick a threshold interval
1420 // that is slightly higher that the minimum interval, and
1421 // spread the blame across all applications with a request
1422 // under that threshold.
1423 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1424 for (UpdateRecord record : records) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001425 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001426 LocationRequest locationRequest = record.mRequest;
1427 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001428 if (record.mReceiver.mWorkSource != null
1429 && record.mReceiver.mWorkSource.size() > 0
1430 && record.mReceiver.mWorkSource.getName(0) != null) {
David Christie82edc9b2013-07-19 11:31:42 -07001431 // Assign blame to another work source.
David Christiee55c9682013-08-22 10:10:34 -07001432 // Can only assign blame if the WorkSource contains names.
David Christie82edc9b2013-07-19 11:31:42 -07001433 worksource.add(record.mReceiver.mWorkSource);
1434 } else {
1435 // Assign blame to caller.
1436 worksource.add(
1437 record.mReceiver.mUid,
1438 record.mReceiver.mPackageName);
1439 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001440 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001441 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 }
1444 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001445
1446 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1447 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 }
1449
1450 private class UpdateRecord {
1451 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001452 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001454 Location mLastFixBroadcast;
1455 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456
1457 /**
1458 * Note: must be constructed with lock held.
1459 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001460 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001462 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464
1465 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1466 if (records == null) {
1467 records = new ArrayList<UpdateRecord>();
1468 mRecordsByProvider.put(provider, records);
1469 }
1470 if (!records.contains(this)) {
1471 records.add(this);
1472 }
David Christie2ff96af2014-01-30 16:09:37 -08001473
1474 // Update statistics for historical location requests by package/provider
1475 mRequestStatistics.startRequesting(
1476 mReceiver.mPackageName, provider, request.getInterval());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 }
1478
1479 /**
David Christie2ff96af2014-01-30 16:09:37 -08001480 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001482 void disposeLocked(boolean removeReceiver) {
David Christie2ff96af2014-01-30 16:09:37 -08001483 mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
1484
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001485 // remove from mRecordsByProvider
1486 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1487 if (globalRecords != null) {
1488 globalRecords.remove(this);
1489 }
1490
1491 if (!removeReceiver) return; // the caller will handle the rest
1492
1493 // remove from Receiver#mUpdateRecords
1494 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1495 if (receiverRecords != null) {
1496 receiverRecords.remove(this.mProvider);
1497
1498 // and also remove the Receiver if it has no more update records
1499 if (removeReceiver && receiverRecords.size() == 0) {
1500 removeUpdatesLocked(mReceiver);
1501 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503 }
1504
1505 @Override
1506 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001507 StringBuilder s = new StringBuilder();
1508 s.append("UpdateRecord[");
1509 s.append(mProvider);
1510 s.append(' ').append(mReceiver.mPackageName).append('(');
1511 s.append(mReceiver.mUid).append(')');
1512 s.append(' ').append(mRequest);
1513 s.append(']');
1514 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 }
1517
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001518 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001519 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001520 IBinder binder = listener.asBinder();
1521 Receiver receiver = mReceivers.get(binder);
1522 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001523 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
1524 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001525 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001526 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001527 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001528 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001529 return null;
1530 }
Wen Jingcb3ab222014-03-27 13:42:59 +08001531 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001532 }
1533 return receiver;
1534 }
1535
David Christie82edc9b2013-07-19 11:31:42 -07001536 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07001537 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001538 Receiver receiver = mReceivers.get(intent);
1539 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07001540 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
1541 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001542 mReceivers.put(intent, receiver);
1543 }
1544 return receiver;
1545 }
1546
Victoria Lease37425c32012-10-16 16:08:48 -07001547 /**
1548 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1549 * and consistency requirements.
1550 *
1551 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07001552 * @return a version of request that meets the given resolution and consistency requirements
1553 * @hide
1554 */
1555 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1556 LocationRequest sanitizedRequest = new LocationRequest(request);
1557 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1558 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001559 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001560 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001561 break;
1562 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001563 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001564 break;
1565 }
1566 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001567 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1568 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001569 }
Victoria Lease37425c32012-10-16 16:08:48 -07001570 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1571 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001572 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001573 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001574 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001575 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001576 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001577 }
Victoria Lease37425c32012-10-16 16:08:48 -07001578 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001579 }
1580
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001581 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001582 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001583 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001584 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001585 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001586 String[] packages = mPackageManager.getPackagesForUid(uid);
1587 if (packages == null) {
1588 throw new SecurityException("invalid UID " + uid);
1589 }
1590 for (String pkg : packages) {
1591 if (packageName.equals(pkg)) return;
1592 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001593 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001594 }
1595
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001596 private void checkPendingIntent(PendingIntent intent) {
1597 if (intent == null) {
1598 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001599 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001600 }
1601
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001602 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07001603 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001604 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001605 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001606 } else if (intent != null && listener != null) {
1607 throw new IllegalArgumentException("cannot register both listener and intent");
1608 } else if (intent != null) {
1609 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07001610 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001611 } else {
David Christie40e57822013-07-30 11:36:48 -07001612 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001613 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001614 }
1615
Nick Pellye0fd6932012-07-11 10:26:13 -07001616 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001617 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1618 PendingIntent intent, String packageName) {
1619 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1620 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001621 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1622 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1623 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07001624 WorkSource workSource = request.getWorkSource();
1625 if (workSource != null && workSource.size() > 0) {
David Christie40e57822013-07-30 11:36:48 -07001626 checkDeviceStatsAllowed();
1627 }
1628 boolean hideFromAppOps = request.getHideFromAppOps();
1629 if (hideFromAppOps) {
1630 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07001631 }
Victoria Lease37425c32012-10-16 16:08:48 -07001632 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001634 final int pid = Binder.getCallingPid();
1635 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001636 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001637 long identity = Binder.clearCallingIdentity();
1638 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001639 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
1640 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07001641 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001642
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001643 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001644 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07001645 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07001646 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 } finally {
1649 Binder.restoreCallingIdentity(identity);
1650 }
1651 }
1652
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001653 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1654 int pid, int uid, String packageName) {
1655 // Figure out the provider. Either its explicitly request (legacy use cases), or
1656 // use the fused provider
1657 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1658 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001659 if (name == null) {
1660 throw new IllegalArgumentException("provider name must not be null");
1661 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07001662
1663 if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
1664 + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001665 LocationProviderInterface provider = mProvidersByName.get(name);
1666 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07001667 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001668 }
1669
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001670 UpdateRecord record = new UpdateRecord(name, request, receiver);
1671 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1672 if (oldRecord != null) {
1673 oldRecord.disposeLocked(false);
1674 }
1675
Victoria Lease09eeaec2013-02-05 11:34:13 -08001676 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001677 if (isProviderEnabled) {
1678 applyRequirementsLocked(name);
1679 } else {
1680 // Notify the listener that updates are currently disabled
1681 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 }
David Christie0b837452013-07-29 16:02:13 -07001683 // Update the monitoring here just in case multiple location requests were added to the
1684 // same receiver (this request may be high power and the initial might not have been).
1685 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 }
1687
Nick Pellye0fd6932012-07-11 10:26:13 -07001688 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001689 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1690 String packageName) {
1691 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001692
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001693 final int pid = Binder.getCallingPid();
1694 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001695
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001696 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07001697 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07001698 boolean hideFromAppOps = false;
1699 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
1700 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001701
1702 // providers may use public location API's, need to clear identity
1703 long identity = Binder.clearCallingIdentity();
1704 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001705 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001706 } finally {
1707 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 }
1710 }
1711
1712 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08001713 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001714
1715 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1716 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1717 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001718 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001719 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 }
1721
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001722 receiver.updateMonitoring(false);
1723
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001724 // Record which providers were associated with this listener
1725 HashSet<String> providers = new HashSet<String>();
1726 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1727 if (oldRecords != null) {
1728 // Call dispose() on the obsolete update records.
1729 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08001730 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001731 record.disposeLocked(false);
1732 }
1733 // Accumulate providers
1734 providers.addAll(oldRecords.keySet());
1735 }
1736
1737 // update provider
1738 for (String provider : providers) {
1739 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08001740 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001741 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 }
1743
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001744 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 }
1746 }
1747
Dianne Hackbornc2293022013-02-06 23:14:49 -08001748 private void applyAllProviderRequirementsLocked() {
1749 for (LocationProviderInterface p : mProviders) {
1750 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08001751 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08001752 continue;
1753 }
1754
1755 applyRequirementsLocked(p.getName());
1756 }
1757 }
1758
Nick Pellye0fd6932012-07-11 10:26:13 -07001759 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001760 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001761 if (D) Log.d(TAG, "getLastLocation: " + request);
1762 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001763 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001764 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001765 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1766 request.getProvider());
1767 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001768
David Christieb870dbf2015-06-22 12:42:53 -07001769 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001770 final int uid = Binder.getCallingUid();
1771 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001772 try {
1773 if (mBlacklist.isBlacklisted(packageName)) {
1774 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1775 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001776 return null;
1777 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001778
David Christieb870dbf2015-06-22 12:42:53 -07001779 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001780 if (D) Log.d(TAG, "not returning last loc for no op app: " +
1781 packageName);
1782 return null;
1783 }
1784
Victoria Leaseb711d572012-10-02 13:14:11 -07001785 synchronized (mLock) {
1786 // Figure out the provider. Either its explicitly request (deprecated API's),
1787 // or use the fused provider
1788 String name = request.getProvider();
1789 if (name == null) name = LocationManager.FUSED_PROVIDER;
1790 LocationProviderInterface provider = mProvidersByName.get(name);
1791 if (provider == null) return null;
1792
Victoria Lease09eeaec2013-02-05 11:34:13 -08001793 if (!isAllowedByUserSettingsLocked(name, uid)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07001794
David Christie1b9b7b12013-04-15 15:31:11 -07001795 Location location;
1796 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1797 // Make sure that an app with coarse permissions can't get frequent location
1798 // updates by calling LocationManager.getLastKnownLocation repeatedly.
1799 location = mLastLocationCoarseInterval.get(name);
1800 } else {
1801 location = mLastLocation.get(name);
1802 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001803 if (location == null) {
1804 return null;
1805 }
Victoria Lease37425c32012-10-16 16:08:48 -07001806 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001807 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1808 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001809 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07001810 }
Victoria Lease37425c32012-10-16 16:08:48 -07001811 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001812 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07001813 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001814 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001815 return null;
1816 } finally {
1817 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001818 }
1819 }
1820
1821 @Override
1822 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1823 String packageName) {
1824 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001825 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1826 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001827 checkPendingIntent(intent);
1828 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001829 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1830 request.getProvider());
1831 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001832
Victoria Lease37425c32012-10-16 16:08:48 -07001833 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001834
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001835 // geo-fence manager uses the public location API, need to clear identity
1836 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07001837 // TODO: http://b/23822629
1838 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08001839 // temporary measure until geofences work for secondary users
1840 Log.w(TAG, "proximity alerts are currently available only to the primary user");
1841 return;
1842 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001843 long identity = Binder.clearCallingIdentity();
1844 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001845 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
1846 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001847 } finally {
1848 Binder.restoreCallingIdentity(identity);
1849 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001850 }
1851
1852 @Override
1853 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001854 checkPendingIntent(intent);
1855 checkPackageName(packageName);
1856
1857 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1858
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001859 // geo-fence manager uses the public location API, need to clear identity
1860 long identity = Binder.clearCallingIdentity();
1861 try {
1862 mGeofenceManager.removeFence(geofence, intent);
1863 } finally {
1864 Binder.restoreCallingIdentity(identity);
1865 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001866 }
1867
1868
1869 @Override
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001870 public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001871 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1872 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001873 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874
David Christieb870dbf2015-06-22 12:42:53 -07001875 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001876 final int uid = Binder.getCallingUid();
1877 final long ident = Binder.clearCallingIdentity();
1878 try {
David Christieb870dbf2015-06-22 12:42:53 -07001879 if (!checkLocationAccess(pid, uid, packageName, allowedResolutionLevel)) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08001880 return false;
1881 }
1882 } finally {
1883 Binder.restoreCallingIdentity(ident);
1884 }
1885
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09001886 if (mGpsStatusProvider == null) {
1887 return false;
1888 }
1889
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001891 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001893 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 return false;
1895 }
1896 return true;
1897 }
1898
Nick Pellye0fd6932012-07-11 10:26:13 -07001899 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001900 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001901 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001902 try {
1903 mGpsStatusProvider.removeGpsStatusListener(listener);
1904 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001905 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001906 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001907 }
1908 }
1909
Nick Pellye0fd6932012-07-11 10:26:13 -07001910 @Override
destradaaea8a8a62014-06-23 18:19:03 -07001911 public boolean addGpsMeasurementsListener(
1912 IGpsMeasurementsListener listener,
1913 String packageName) {
1914 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1915 checkResolutionLevelIsSufficientForProviderUse(
1916 allowedResolutionLevel,
1917 LocationManager.GPS_PROVIDER);
1918
David Christieb870dbf2015-06-22 12:42:53 -07001919 int pid = Binder.getCallingPid();
destradaaea8a8a62014-06-23 18:19:03 -07001920 int uid = Binder.getCallingUid();
1921 long identity = Binder.clearCallingIdentity();
1922 boolean hasLocationAccess;
1923 try {
David Christieb870dbf2015-06-22 12:42:53 -07001924 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
destradaaea8a8a62014-06-23 18:19:03 -07001925 } finally {
1926 Binder.restoreCallingIdentity(identity);
1927 }
1928
Wei Liu5241a4c2015-05-11 14:00:36 -07001929 if (!hasLocationAccess || mGpsMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07001930 return false;
1931 }
destradaaea8a8a62014-06-23 18:19:03 -07001932 return mGpsMeasurementsProvider.addListener(listener);
1933 }
1934
1935 @Override
destradaa6568d702014-10-27 12:47:41 -07001936 public void removeGpsMeasurementsListener(IGpsMeasurementsListener listener) {
Wei Liu5241a4c2015-05-11 14:00:36 -07001937 if (mGpsMeasurementsProvider != null) {
1938 mGpsMeasurementsProvider.removeListener(listener);
1939 }
destradaaea8a8a62014-06-23 18:19:03 -07001940 }
1941
1942 @Override
destradaa4b3e3932014-07-21 18:01:47 -07001943 public boolean addGpsNavigationMessageListener(
1944 IGpsNavigationMessageListener listener,
1945 String packageName) {
1946 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1947 checkResolutionLevelIsSufficientForProviderUse(
1948 allowedResolutionLevel,
1949 LocationManager.GPS_PROVIDER);
1950
David Christieb870dbf2015-06-22 12:42:53 -07001951 int pid = Binder.getCallingPid();
destradaa4b3e3932014-07-21 18:01:47 -07001952 int uid = Binder.getCallingUid();
1953 long identity = Binder.clearCallingIdentity();
1954 boolean hasLocationAccess;
1955 try {
David Christieb870dbf2015-06-22 12:42:53 -07001956 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
destradaa4b3e3932014-07-21 18:01:47 -07001957 } finally {
1958 Binder.restoreCallingIdentity(identity);
1959 }
1960
Wei Liu5241a4c2015-05-11 14:00:36 -07001961 if (!hasLocationAccess || mGpsNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07001962 return false;
1963 }
1964 return mGpsNavigationMessageProvider.addListener(listener);
1965 }
1966
1967 @Override
destradaa6568d702014-10-27 12:47:41 -07001968 public void removeGpsNavigationMessageListener(IGpsNavigationMessageListener listener) {
Wei Liu5241a4c2015-05-11 14:00:36 -07001969 if (mGpsNavigationMessageProvider != null) {
1970 mGpsNavigationMessageProvider.removeListener(listener);
1971 }
destradaa4b3e3932014-07-21 18:01:47 -07001972 }
1973
1974 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001976 if (provider == null) {
1977 // throw NullPointerException to remain compatible with previous implementation
1978 throw new NullPointerException();
1979 }
Victoria Lease37425c32012-10-16 16:08:48 -07001980 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1981 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001984 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985 != PackageManager.PERMISSION_GRANTED)) {
1986 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1987 }
1988
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001989 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001990 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001991 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001992
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001993 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 }
1995 }
1996
Nick Pellye0fd6932012-07-11 10:26:13 -07001997 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001998 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001999 if (Binder.getCallingUid() != Process.myUid()) {
2000 throw new SecurityException(
2001 "calling sendNiResponse from outside of the system is not allowed");
2002 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002003 try {
2004 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002005 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002006 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002007 return false;
2008 }
2009 }
2010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002011 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002012 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11002013 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002014 * accessed by the caller
2015 */
Nick Pellye0fd6932012-07-11 10:26:13 -07002016 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002017 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07002018 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08002019 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07002020 }
2021
Victoria Lease37425c32012-10-16 16:08:48 -07002022 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2023 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002025 LocationProviderInterface p;
2026 synchronized (mLock) {
2027 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 }
2029
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002030 if (p == null) return null;
2031 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 }
2033
Jason Monkb71218a2015-06-17 14:44:39 -04002034 /**
2035 * @return null if the provider does not exist
2036 * @throws SecurityException if the provider is not allowed to be
2037 * accessed by the caller
2038 */
2039 @Override
2040 public String getNetworkProviderPackage() {
2041 LocationProviderInterface p;
2042 synchronized (mLock) {
2043 if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2044 return null;
2045 }
2046 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2047 }
2048
2049 if (p instanceof LocationProviderProxy) {
2050 return ((LocationProviderProxy) p).getConnectedPackageName();
2051 }
2052 return null;
2053 }
2054
Nick Pellye0fd6932012-07-11 10:26:13 -07002055 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 public boolean isProviderEnabled(String provider) {
Tom O'Neilld5759432013-09-11 11:03:03 -07002057 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2058 // so we discourage its use
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002059 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2060
Victoria Lease09eeaec2013-02-05 11:34:13 -08002061 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07002062 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002063 try {
2064 synchronized (mLock) {
2065 LocationProviderInterface p = mProvidersByName.get(provider);
2066 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002067
Victoria Lease09eeaec2013-02-05 11:34:13 -08002068 return isAllowedByUserSettingsLocked(provider, uid);
Victoria Leaseb711d572012-10-02 13:14:11 -07002069 }
2070 } finally {
2071 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002072 }
2073 }
2074
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002075 /**
2076 * Returns "true" if the UID belongs to a bound location provider.
2077 *
2078 * @param uid the uid
2079 * @return true if uid belongs to a bound location provider
2080 */
2081 private boolean isUidALocationProvider(int uid) {
2082 if (uid == Process.SYSTEM_UID) {
2083 return true;
2084 }
2085 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002086 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002087 }
2088 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002089 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002090 }
2091 return false;
2092 }
2093
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002094 private void checkCallerIsProvider() {
2095 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
2096 == PackageManager.PERMISSION_GRANTED) {
2097 return;
2098 }
2099
2100 // Previously we only used the INSTALL_LOCATION_PROVIDER
2101 // check. But that is system or signature
2102 // protection level which is not flexible enough for
2103 // providers installed oustide the system image. So
2104 // also allow providers with a UID matching the
2105 // currently bound package name
2106
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002107 if (isUidALocationProvider(Binder.getCallingUid())) {
2108 return;
2109 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002110
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002111 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2112 "or UID of a currently bound location provider");
2113 }
2114
David Christie1f141c12014-05-14 15:11:15 -07002115 /**
2116 * Returns true if the given package belongs to the given uid.
2117 */
2118 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002119 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 return false;
2121 }
David Christie1f141c12014-05-14 15:11:15 -07002122 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2123 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002124 return false;
2125 }
David Christie1f141c12014-05-14 15:11:15 -07002126 for (String name : packageNames) {
2127 if (packageName.equals(name)) {
2128 return true;
2129 }
2130 }
2131 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 }
2133
Nick Pellye0fd6932012-07-11 10:26:13 -07002134 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002135 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002136 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002137
Nick Pelly2eeeec22012-07-18 13:13:37 -07002138 if (!location.isComplete()) {
2139 Log.w(TAG, "Dropping incomplete location: " + location);
2140 return;
2141 }
2142
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002143 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2144 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002145 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002146 mLocationHandler.sendMessageAtFrontOfQueue(m);
2147 }
2148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002149
Laurent Tu75defb62012-11-01 16:21:52 -07002150 private static boolean shouldBroadcastSafe(
2151 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 // Always broadcast the first update
2153 if (lastLoc == null) {
2154 return true;
2155 }
2156
Nick Pellyf1be6862012-05-15 10:53:42 -07002157 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002158 long minTime = record.mRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002159 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2160 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002161 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002162 return false;
2163 }
2164
2165 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002166 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 if (minDistance > 0.0) {
2168 if (loc.distanceTo(lastLoc) <= minDistance) {
2169 return false;
2170 }
2171 }
2172
Laurent Tu75defb62012-11-01 16:21:52 -07002173 // Check whether sufficient number of udpates is left
2174 if (record.mRequest.getNumUpdates() <= 0) {
2175 return false;
2176 }
2177
2178 // Check whether the expiry date has passed
2179 if (record.mRequest.getExpireAt() < now) {
2180 return false;
2181 }
2182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 return true;
2184 }
2185
Mike Lockwooda4903f22010-02-17 06:42:23 -05002186 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002187 if (D) Log.d(TAG, "incoming location: " + location);
2188
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002189 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002190 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002191
Laurent Tu60ec50a2012-10-04 17:00:10 -07002192 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002193 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002194 if (p == null) return;
2195
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002196 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07002197 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2198 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002199 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002200 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002201 lastLocation = new Location(provider);
2202 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07002203 } else {
2204 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2205 if (noGPSLocation == null && lastNoGPSLocation != null) {
2206 // New location has no no-GPS location: adopt last no-GPS location. This is set
2207 // directly into location because we do not want to notify COARSE clients.
2208 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
2209 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07002210 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002211 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212
David Christie1b9b7b12013-04-15 15:31:11 -07002213 // Update last known coarse interval location if enough time has passed.
2214 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2215 if (lastLocationCoarseInterval == null) {
2216 lastLocationCoarseInterval = new Location(location);
2217 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2218 }
2219 long timeDiffNanos = location.getElapsedRealtimeNanos()
2220 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2221 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2222 lastLocationCoarseInterval.set(location);
2223 }
2224 // Don't ever return a coarse location that is more recent than the allowed update
2225 // interval (i.e. don't allow an app to keep registering and unregistering for
2226 // location updates to overcome the minimum interval).
2227 noGPSLocation =
2228 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2229
Laurent Tu60ec50a2012-10-04 17:00:10 -07002230 // Skip if there are no UpdateRecords for this provider.
2231 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2232 if (records == null || records.size() == 0) return;
2233
Victoria Lease09016ab2012-09-16 12:33:15 -07002234 // Fetch coarse location
2235 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002236 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002237 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2238 }
2239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 // Fetch latest status update time
2241 long newStatusUpdateTime = p.getStatusUpdateTime();
2242
David Christie2ff96af2014-01-30 16:09:37 -08002243 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002244 Bundle extras = new Bundle();
2245 int status = p.getStatus(extras);
2246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002247 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002248 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002251 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002252 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002253 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002254
Victoria Lease269518e2012-10-29 08:25:39 -07002255 int receiverUserId = UserHandle.getUserId(receiver.mUid);
Amith Yamasanib27528d2014-06-05 15:02:10 -07002256 if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002257 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002258 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002259 " (current user: " + mCurrentUserId + ", app: " +
2260 receiver.mPackageName + ")");
2261 }
2262 continue;
2263 }
2264
Nick Pelly4035f5a2012-08-17 14:43:49 -07002265 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
2266 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
2267 receiver.mPackageName);
2268 continue;
2269 }
2270
David Christieb870dbf2015-06-22 12:42:53 -07002271 if (!reportLocationAccessNoThrow(receiver.mPid, receiver.mUid, receiver.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002272 receiver.mAllowedResolutionLevel)) {
2273 if (D) Log.d(TAG, "skipping loc update for no op app: " +
2274 receiver.mPackageName);
2275 continue;
2276 }
2277
Victoria Lease09016ab2012-09-16 12:33:15 -07002278 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07002279 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2280 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002281 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002282 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002283 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002284 if (notifyLocation != null) {
2285 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002286 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002287 if (lastLoc == null) {
2288 lastLoc = new Location(notifyLocation);
2289 r.mLastFixBroadcast = lastLoc;
2290 } else {
2291 lastLoc.set(notifyLocation);
2292 }
2293 if (!receiver.callLocationChangedLocked(notifyLocation)) {
2294 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
2295 receiverDead = true;
2296 }
Laurent Tu75defb62012-11-01 16:21:52 -07002297 r.mRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002298 }
2299 }
2300
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002301 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002302 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07002303 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002304
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002305 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002306 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002307 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08002308 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07002309 }
2310 }
2311
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002312 // track expired records
Laurent Tu75defb62012-11-01 16:21:52 -07002313 if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002314 if (deadUpdateRecords == null) {
2315 deadUpdateRecords = new ArrayList<UpdateRecord>();
2316 }
2317 deadUpdateRecords.add(r);
2318 }
2319 // track dead receivers
2320 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07002321 if (deadReceivers == null) {
2322 deadReceivers = new ArrayList<Receiver>();
2323 }
2324 if (!deadReceivers.contains(receiver)) {
2325 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002326 }
2327 }
2328 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002329
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002330 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002331 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002332 for (Receiver receiver : deadReceivers) {
2333 removeUpdatesLocked(receiver);
2334 }
2335 }
2336 if (deadUpdateRecords != null) {
2337 for (UpdateRecord r : deadUpdateRecords) {
2338 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002339 }
Victoria Lease8b38b292012-12-04 15:04:43 -08002340 applyRequirementsLocked(provider);
2341 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002342 }
2343
2344 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08002345 public LocationWorkerHandler(Looper looper) {
2346 super(looper, null, true);
2347 }
2348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002349 @Override
2350 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002351 switch (msg.what) {
2352 case MSG_LOCATION_CHANGED:
2353 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
2354 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002355 }
2356 }
2357 }
2358
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002359 private boolean isMockProvider(String provider) {
2360 synchronized (mLock) {
2361 return mMockProviders.containsKey(provider);
2362 }
2363 }
2364
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002365 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002366 // create a working copy of the incoming Location so that the service can modify it without
2367 // disturbing the caller's copy
2368 Location myLocation = new Location(location);
2369 String provider = myLocation.getProvider();
2370
2371 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2372 // bit if location did not come from a mock provider because passive/fused providers can
2373 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2374 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
2375 myLocation.setIsFromMockProvider(true);
2376 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08002377
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002378 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08002379 if (isAllowedByCurrentUserSettingsLocked(provider)) {
2380 if (!passive) {
2381 // notify passive provider of the new location
2382 mPassiveProvider.updateLocation(myLocation);
2383 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08002384 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002385 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002386 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002387 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002388
Mike Lockwoode97ae402010-09-29 15:23:46 -04002389 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
2390 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002391 public void onPackageDisappeared(String packageName, int reason) {
2392 // remove all receivers associated with this package name
2393 synchronized (mLock) {
2394 ArrayList<Receiver> deadReceivers = null;
2395
2396 for (Receiver receiver : mReceivers.values()) {
2397 if (receiver.mPackageName.equals(packageName)) {
2398 if (deadReceivers == null) {
2399 deadReceivers = new ArrayList<Receiver>();
2400 }
2401 deadReceivers.add(receiver);
2402 }
2403 }
2404
2405 // perform removal outside of mReceivers loop
2406 if (deadReceivers != null) {
2407 for (Receiver receiver : deadReceivers) {
2408 removeUpdatesLocked(receiver);
2409 }
2410 }
2411 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002412 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04002413 };
2414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002415 // Geocoder
2416
Nick Pellye0fd6932012-07-11 10:26:13 -07002417 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04002418 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07002419 return mGeocodeProvider != null;
2420 }
2421
Nick Pellye0fd6932012-07-11 10:26:13 -07002422 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002423 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002424 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002425 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002426 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
2427 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002428 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002429 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 }
2431
Mike Lockwooda55c3212009-04-15 11:10:11 -04002432
Nick Pellye0fd6932012-07-11 10:26:13 -07002433 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002434 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04002435 double lowerLeftLatitude, double lowerLeftLongitude,
2436 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05002437 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04002438
2439 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002440 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
2441 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
2442 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002443 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04002444 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002445 }
2446
2447 // Mock Providers
2448
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002449 private boolean canCallerAccessMockLocation(String opPackageName) {
2450 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
2451 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002452 }
2453
Nick Pellye0fd6932012-07-11 10:26:13 -07002454 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002455 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
2456 if (!canCallerAccessMockLocation(opPackageName)) {
2457 return;
2458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002459
Mike Lockwooda4903f22010-02-17 06:42:23 -05002460 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
2461 throw new IllegalArgumentException("Cannot mock the passive location provider");
2462 }
2463
Mike Lockwood86328a92009-10-23 08:38:25 -04002464 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002465 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002466 // remove the real provider if we are replacing GPS or network provider
2467 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07002468 || LocationManager.NETWORK_PROVIDER.equals(name)
2469 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002470 LocationProviderInterface p = mProvidersByName.get(name);
2471 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002472 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002473 }
2474 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002475 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002476 updateProvidersLocked();
2477 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002478 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002479 }
2480
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09002481 private void addTestProviderLocked(String name, ProviderProperties properties) {
2482 if (mProvidersByName.get(name) != null) {
2483 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2484 }
2485 MockProvider provider = new MockProvider(name, this, properties);
2486 addProviderLocked(provider);
2487 mMockProviders.put(name, provider);
2488 mLastLocation.put(name, null);
2489 mLastLocationCoarseInterval.put(name, null);
2490 }
2491
Nick Pellye0fd6932012-07-11 10:26:13 -07002492 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002493 public void removeTestProvider(String provider, String opPackageName) {
2494 if (!canCallerAccessMockLocation(opPackageName)) {
2495 return;
2496 }
2497
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002498 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002499
2500 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08002501 // we don't leave anything dangling.
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002502 clearTestProviderEnabled(provider, opPackageName);
2503 clearTestProviderLocation(provider, opPackageName);
2504 clearTestProviderStatus(provider, opPackageName);
Tom O'Neill07ee5d12014-03-03 17:48:35 -08002505
You Kima6d0b6f2012-10-28 03:58:44 +09002506 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002507 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002508 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2509 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002510 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002511 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002512
2513 // reinstate real provider if available
2514 LocationProviderInterface realProvider = mRealProviders.get(provider);
2515 if (realProvider != null) {
2516 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07002517 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002518 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07002519 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002520 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002521 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002522 }
2523 }
2524
Nick Pellye0fd6932012-07-11 10:26:13 -07002525 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002526 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
2527 if (!canCallerAccessMockLocation(opPackageName)) {
2528 return;
2529 }
2530
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002531 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002532 MockProvider mockProvider = mMockProviders.get(provider);
2533 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002534 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2535 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04002536 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2537 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002538 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04002539 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 }
2541 }
2542
Nick Pellye0fd6932012-07-11 10:26:13 -07002543 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002544 public void clearTestProviderLocation(String provider, String opPackageName) {
2545 if (!canCallerAccessMockLocation(opPackageName)) {
2546 return;
2547 }
2548
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002549 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002550 MockProvider mockProvider = mMockProviders.get(provider);
2551 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002552 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2553 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002554 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002555 }
2556 }
2557
Nick Pellye0fd6932012-07-11 10:26:13 -07002558 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002559 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
2560 if (!canCallerAccessMockLocation(opPackageName)) {
2561 return;
2562 }
2563
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002564 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002565 MockProvider mockProvider = mMockProviders.get(provider);
2566 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002567 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2568 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002569 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002570 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002571 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002572 mEnabledProviders.add(provider);
2573 mDisabledProviders.remove(provider);
2574 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002575 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002576 mEnabledProviders.remove(provider);
2577 mDisabledProviders.add(provider);
2578 }
2579 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002580 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002581 }
2582 }
2583
Nick Pellye0fd6932012-07-11 10:26:13 -07002584 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002585 public void clearTestProviderEnabled(String provider, String opPackageName) {
2586 if (!canCallerAccessMockLocation(opPackageName)) {
2587 return;
2588 }
2589
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002590 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002591 MockProvider mockProvider = mMockProviders.get(provider);
2592 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002593 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2594 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002595 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002596 mEnabledProviders.remove(provider);
2597 mDisabledProviders.remove(provider);
2598 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002599 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002600 }
2601 }
2602
Nick Pellye0fd6932012-07-11 10:26:13 -07002603 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002604 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
2605 String opPackageName) {
2606 if (!canCallerAccessMockLocation(opPackageName)) {
2607 return;
2608 }
2609
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002610 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002611 MockProvider mockProvider = mMockProviders.get(provider);
2612 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002613 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2614 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002615 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 }
2617 }
2618
Nick Pellye0fd6932012-07-11 10:26:13 -07002619 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07002620 public void clearTestProviderStatus(String provider, String opPackageName) {
2621 if (!canCallerAccessMockLocation(opPackageName)) {
2622 return;
2623 }
2624
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002625 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002626 MockProvider mockProvider = mMockProviders.get(provider);
2627 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2629 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002630 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002631 }
2632 }
2633
2634 private void log(String log) {
2635 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002636 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002637 }
2638 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002639
2640 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002641 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2642 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2643 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002644 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002645 + Binder.getCallingPid()
2646 + ", uid=" + Binder.getCallingUid());
2647 return;
2648 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002649
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002650 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002651 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002653 for (Receiver receiver : mReceivers.values()) {
2654 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002655 }
David Christie2ff96af2014-01-30 16:09:37 -08002656 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002657 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
2658 pw.println(" " + entry.getKey() + ":");
2659 for (UpdateRecord record : entry.getValue()) {
2660 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002661 }
2662 }
David Christie2ff96af2014-01-30 16:09:37 -08002663 pw.println(" Historical Records by Provider:");
2664 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
2665 : mRequestStatistics.statistics.entrySet()) {
2666 PackageProviderKey key = entry.getKey();
2667 PackageStatistics stats = entry.getValue();
2668 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
2669 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002670 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002671 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
2672 String provider = entry.getKey();
2673 Location location = entry.getValue();
2674 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002675 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002676
David Christie1b9b7b12013-04-15 15:31:11 -07002677 pw.println(" Last Known Locations Coarse Intervals:");
2678 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
2679 String provider = entry.getKey();
2680 Location location = entry.getValue();
2681 pw.println(" " + provider + ": " + location);
2682 }
2683
Nick Pellye0fd6932012-07-11 10:26:13 -07002684 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002686 if (mEnabledProviders.size() > 0) {
2687 pw.println(" Enabled Providers:");
2688 for (String i : mEnabledProviders) {
2689 pw.println(" " + i);
2690 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002692 }
2693 if (mDisabledProviders.size() > 0) {
2694 pw.println(" Disabled Providers:");
2695 for (String i : mDisabledProviders) {
2696 pw.println(" " + i);
2697 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002698 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002699 pw.append(" ");
2700 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002701 if (mMockProviders.size() > 0) {
2702 pw.println(" Mock Providers:");
2703 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002704 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002705 }
2706 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002707
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002708 pw.append(" fudger: ");
2709 mLocationFudger.dump(fd, pw, args);
2710
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002711 if (args.length > 0 && "short".equals(args[0])) {
2712 return;
2713 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002714 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002715 pw.print(provider.getName() + " Internal State");
2716 if (provider instanceof LocationProviderProxy) {
2717 LocationProviderProxy proxy = (LocationProviderProxy) provider;
2718 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002719 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002720 pw.println(":");
2721 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002722 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002723 }
2724 }
2725}