blob: 232c151f0418a04c96be79c90907697629918627 [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
Maggieaa080f92018-01-04 15:35:11 -080019import static android.content.pm.PackageManager.PERMISSION_GRANTED;
20
Wyatt Rileycf879db2017-01-12 13:57:38 -080021import android.annotation.NonNull;
Wyatt Riley49097c02018-03-15 09:14:43 -070022import android.annotation.Nullable;
Maggieaa080f92018-01-04 15:35:11 -080023import android.app.ActivityManager;
24import android.app.AppOpsManager;
25import android.app.PendingIntent;
26import android.content.BroadcastReceiver;
27import android.content.ContentResolver;
28import android.content.Context;
29import android.content.Intent;
30import android.content.IntentFilter;
31import android.content.pm.ApplicationInfo;
32import android.content.pm.PackageInfo;
33import android.content.pm.PackageManager;
34import android.content.pm.PackageManager.NameNotFoundException;
35import android.content.pm.PackageManagerInternal;
36import android.content.pm.ResolveInfo;
37import android.content.pm.Signature;
38import android.content.res.Resources;
39import android.database.ContentObserver;
40import android.hardware.location.ActivityRecognitionHardware;
41import android.location.Address;
42import android.location.Criteria;
43import android.location.GeocoderParams;
44import android.location.Geofence;
45import android.location.IBatchedLocationCallback;
46import android.location.IGnssMeasurementsListener;
47import android.location.IGnssNavigationMessageListener;
48import android.location.IGnssStatusListener;
49import android.location.IGnssStatusProvider;
50import android.location.IGpsGeofenceHardware;
51import android.location.ILocationListener;
52import android.location.ILocationManager;
53import android.location.INetInitiatedListener;
54import android.location.Location;
55import android.location.LocationManager;
56import android.location.LocationProvider;
57import android.location.LocationRequest;
58import android.os.Binder;
59import android.os.Bundle;
60import android.os.Handler;
61import android.os.IBinder;
62import android.os.Looper;
63import android.os.Message;
64import android.os.PowerManager;
65import android.os.Process;
66import android.os.RemoteException;
67import android.os.SystemClock;
68import android.os.UserHandle;
69import android.os.UserManager;
70import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000071import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080072import android.provider.Settings;
73import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080074import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080075import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080076import android.util.EventLog;
77import android.util.Log;
78import android.util.Slog;
destradaaea8a8a62014-06-23 18:19:03 -070079import com.android.internal.content.PackageMonitor;
80import com.android.internal.location.ProviderProperties;
81import com.android.internal.location.ProviderRequest;
82import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070083import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060084import com.android.internal.util.DumpUtils;
destradaaa4fa3b52014-07-09 10:46:39 -070085import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070086import com.android.server.location.GeocoderProxy;
87import com.android.server.location.GeofenceManager;
88import com.android.server.location.GeofenceProxy;
Yu-Han Yang3557cc72018-03-21 12:48:36 -070089import com.android.server.location.GnssBatchingProvider;
Lifu Tang818aa2c2016-02-01 01:52:00 -080090import com.android.server.location.GnssLocationProvider;
91import com.android.server.location.GnssMeasurementsProvider;
92import com.android.server.location.GnssNavigationMessageProvider;
destradaaea8a8a62014-06-23 18:19:03 -070093import com.android.server.location.LocationBlacklist;
94import com.android.server.location.LocationFudger;
95import com.android.server.location.LocationProviderInterface;
96import com.android.server.location.LocationProviderProxy;
97import com.android.server.location.LocationRequestStatistics;
98import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
99import com.android.server.location.LocationRequestStatistics.PackageStatistics;
100import com.android.server.location.MockProvider;
101import com.android.server.location.PassiveProvider;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400102import java.io.FileDescriptor;
103import java.io.PrintWriter;
104import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700105import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400106import java.util.HashMap;
107import java.util.HashSet;
108import java.util.List;
109import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800110import java.util.Map.Entry;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800111import java.util.NoSuchElementException;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400112import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
114/**
115 * The service class that manages LocationProviders and issues location
116 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800118public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800120 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700121
Olivier Gaillard7a222662017-11-20 16:07:24 +0000122 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
Victoria Lease37425c32012-10-16 16:08:48 -0700124 // Location resolution level: no location data whatsoever
125 private static final int RESOLUTION_LEVEL_NONE = 0;
126 // Location resolution level: coarse location data only
127 private static final int RESOLUTION_LEVEL_COARSE = 1;
128 // Location resolution level: fine location data
129 private static final int RESOLUTION_LEVEL_FINE = 2;
130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700132 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700134 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400135 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700136 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
137
138 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700139 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700140 private static final String FUSED_LOCATION_SERVICE_ACTION =
141 "com.android.location.service.FusedLocationProvider";
142
143 private static final int MSG_LOCATION_CHANGED = 1;
144
David Christie1b9b7b12013-04-15 15:31:11 -0700145 private static final long NANOS_PER_MILLI = 1000000L;
146
David Christie0b837452013-07-29 16:02:13 -0700147 // The maximum interval a location request can have and still be considered "high power".
148 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
149
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700150 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800151 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700152
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800153 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800154 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800155
Wei Wangdd070f22018-06-21 11:29:40 -0700156 // Default value for maximum age of last location returned to applications with foreground-only
157 // location permissions.
158 private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
159
Nick Pellyf1be6862012-05-15 10:53:42 -0700160 // Location Providers may sometimes deliver location updates
161 // slightly faster that requested - provide grace period so
162 // we don't unnecessarily filter events that are otherwise on
163 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700164 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700165
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700166 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
167
168 private final Context mContext;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800169 private final AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700170
171 // used internally for synchronization
172 private final Object mLock = new Object();
173
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700174 // --- fields below are final after systemRunning() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700175 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700176 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700177 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700178 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800179 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700180 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 private GeocoderProxy mGeocodeProvider;
Lifu Tang30f95a72016-01-07 23:20:38 -0800182 private IGnssStatusProvider mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 private INetInitiatedListener mNetInitiatedListener;
184 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700185 private PassiveProvider mPassiveProvider; // track passive provider for special cases
186 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800187 private GnssMeasurementsProvider mGnssMeasurementsProvider;
188 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Wei Liu5241a4c2015-05-11 14:00:36 -0700189 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700190
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700191 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 // Set of providers that are explicitly enabled
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700193 // Only used by passive, fused & test. Network & GPS are controlled separately, and not listed.
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800194 private final Set<String> mEnabledProviders = new HashSet<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
196 // Set of providers that are explicitly disabled
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800197 private final Set<String> mDisabledProviders = new HashSet<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700199 // Mock (test) providers
200 private final HashMap<String, MockProvider> mMockProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800201 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700203 // all receivers
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800204 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700206 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500207 private final ArrayList<LocationProviderInterface> mProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800208 new ArrayList<>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400209
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700210 // real providers, saved here when mocked out
211 private final HashMap<String, LocationProviderInterface> mRealProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800212 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700214 // mapping from provider name to provider
215 private final HashMap<String, LocationProviderInterface> mProvidersByName =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800216 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700218 // mapping from provider name to all its UpdateRecords
219 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800220 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700221
David Christie2ff96af2014-01-30 16:09:37 -0800222 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
223
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700224 // mapping from provider name to last known location
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800225 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226
David Christie1b9b7b12013-04-15 15:31:11 -0700227 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
228 // locations stored here are not fudged for coarse permissions.
229 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800230 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700231
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800232 // all providers that operate over proxy, for authorizing incoming location and whitelisting
233 // throttling
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700234 private final ArrayList<LocationProviderProxy> mProxyProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800235 new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800237 private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800238
Wyatt Riley11cc7492018-01-17 08:48:27 -0800239 private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800240
Wyatt Riley11cc7492018-01-17 08:48:27 -0800241 private final ArrayMap<IBinder, Identity>
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800242 mGnssNavigationMessageListeners = new ArrayMap<>();
243
Victoria Lease38389b62012-09-30 11:44:22 -0700244 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700245 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800246 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700247
Wei Wangdd070f22018-06-21 11:29:40 -0700248 // Maximum age of last location returned to clients with foreground-only location permissions.
249 private long mLastLocationMaxAgeMs;
250
Lifu Tang9363b942016-02-16 18:07:00 -0800251 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800252
Siddharth Raybb608c82017-03-16 11:33:34 -0700253 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700254
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700255 private GnssBatchingProvider mGnssBatchingProvider;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800256 private IBatchedLocationCallback mGnssBatchingCallback;
257 private LinkedCallback mGnssBatchingDeathCallback;
258 private boolean mGnssBatchingInProgress = false;
259
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700260 public LocationManagerService(Context context) {
261 super();
262 mContext = context;
gomo48f1a642017-11-10 20:35:46 -0800263 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800264
Svet Ganovadc1cf42015-06-15 16:36:24 -0700265 // Let the package manager query which are the default location
266 // providers as they get certain permissions granted by default.
267 PackageManagerInternal packageManagerInternal = LocalServices.getService(
268 PackageManagerInternal.class);
269 packageManagerInternal.setLocationPackagesProvider(
270 new PackageManagerInternal.PackagesProvider() {
271 @Override
272 public String[] getPackages(int userId) {
273 return mContext.getResources().getStringArray(
274 com.android.internal.R.array.config_locationProviderPackageNames);
275 }
276 });
277
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700278 if (D) Log.d(TAG, "Constructed");
279
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700280 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700281 }
282
Svetoslav Ganova0027152013-06-25 14:59:53 -0700283 public void systemRunning() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700284 synchronized (mLock) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700285 if (D) Log.d(TAG, "systemRunning()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700286
Victoria Lease5cd731a2012-12-19 15:04:21 -0800287 // fetch package manager
288 mPackageManager = mContext.getPackageManager();
289
Victoria Lease0aa28602013-05-29 15:28:26 -0700290 // fetch power manager
291 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800292
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800293 // fetch activity manager
294 mActivityManager
295 = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
296
Victoria Lease5cd731a2012-12-19 15:04:21 -0800297 // prepare worker thread
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700298 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800299
300 // prepare mLocationHandler's dependents
301 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
302 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
303 mBlacklist.init();
304 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
305
Dianne Hackbornc2293022013-02-06 23:14:49 -0800306 // Monitor for app ops mode changes.
Dianne Hackborn9bb0ee92013-09-22 12:31:38 -0700307 AppOpsManager.OnOpChangedListener callback
308 = new AppOpsManager.OnOpChangedInternalListener() {
309 public void onOpChanged(int op, String packageName) {
Dianne Hackbornc2293022013-02-06 23:14:49 -0800310 synchronized (mLock) {
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700311 for (Receiver receiver : mReceivers.values()) {
312 receiver.updateMonitoring(true);
313 }
Dianne Hackbornc2293022013-02-06 23:14:49 -0800314 applyAllProviderRequirementsLocked();
315 }
316 }
317 };
Wei Wangdd070f22018-06-21 11:29:40 -0700318 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
319 AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800320
David Christieb870dbf2015-06-22 12:42:53 -0700321 PackageManager.OnPermissionsChangedListener permissionListener
322 = new PackageManager.OnPermissionsChangedListener() {
323 @Override
324 public void onPermissionsChanged(final int uid) {
325 synchronized (mLock) {
326 applyAllProviderRequirementsLocked();
327 }
328 }
329 };
330 mPackageManager.addOnPermissionsChangeListener(permissionListener);
331
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800332 // listen for background/foreground changes
333 ActivityManager.OnUidImportanceListener uidImportanceListener
334 = new ActivityManager.OnUidImportanceListener() {
335 @Override
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700336 public void onUidImportance(final int uid, final int importance) {
337 mLocationHandler.post(new Runnable() {
338 @Override
339 public void run() {
340 onUidImportanceChanged(uid, importance);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800341 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700342 });
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800343 }
344 };
345 mActivityManager.addOnUidImportanceListener(uidImportanceListener,
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700346 FOREGROUND_IMPORTANCE_CUTOFF);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800347
Amith Yamasanib27528d2014-06-05 15:02:10 -0700348 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
349 updateUserProfiles(mCurrentUserId);
350
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800351 updateBackgroundThrottlingWhitelistLocked();
Wei Wangdd070f22018-06-21 11:29:40 -0700352 updateLastLocationMaxAgeLocked();
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800353
Victoria Lease5cd731a2012-12-19 15:04:21 -0800354 // prepare providers
355 loadProvidersLocked();
356 updateProvidersLocked();
357 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700358
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700359 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700360 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700361 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700362 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800363 @Override
364 public void onChange(boolean selfChange) {
365 synchronized (mLock) {
366 updateProvidersLocked();
367 }
368 }
369 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800370 mContext.getContentResolver().registerContentObserver(
371 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
372 true,
373 new ContentObserver(mLocationHandler) {
374 @Override
375 public void onChange(boolean selfChange) {
376 synchronized (mLock) {
377 updateProvidersLocked();
378 }
379 }
380 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800381 mContext.getContentResolver().registerContentObserver(
Wei Wangdd070f22018-06-21 11:29:40 -0700382 Settings.Global.getUriFor(Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS),
383 true,
384 new ContentObserver(mLocationHandler) {
385 @Override
386 public void onChange(boolean selfChange) {
387 synchronized (mLock) {
388 updateLastLocationMaxAgeLocked();
389 }
390 }
391 }
392 );
393 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800394 Settings.Global.getUriFor(
395 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
396 true,
397 new ContentObserver(mLocationHandler) {
398 @Override
399 public void onChange(boolean selfChange) {
400 synchronized (mLock) {
401 updateBackgroundThrottlingWhitelistLocked();
402 updateProvidersLocked();
403 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800404 }
gomo48f1a642017-11-10 20:35:46 -0800405 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700406
Victoria Lease5cd731a2012-12-19 15:04:21 -0800407 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700408
Victoria Lease38389b62012-09-30 11:44:22 -0700409 // listen for user change
410 IntentFilter intentFilter = new IntentFilter();
411 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700412 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
413 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
destradaab9026982015-08-27 17:34:54 -0700414 intentFilter.addAction(Intent.ACTION_SHUTDOWN);
Victoria Lease38389b62012-09-30 11:44:22 -0700415
416 mContext.registerReceiverAsUser(new BroadcastReceiver() {
417 @Override
418 public void onReceive(Context context, Intent intent) {
419 String action = intent.getAction();
420 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
421 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700422 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
423 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
424 updateUserProfiles(mCurrentUserId);
destradaab9026982015-08-27 17:34:54 -0700425 } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700426 // shutdown only if UserId indicates whole system, not just one user
gomo48f1a642017-11-10 20:35:46 -0800427 if (D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId());
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700428 if (getSendingUserId() == UserHandle.USER_ALL) {
429 shutdownComponents();
430 }
Victoria Lease38389b62012-09-30 11:44:22 -0700431 }
432 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800433 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700434 }
435
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700436 private void onUidImportanceChanged(int uid, int importance) {
437 boolean foreground = isImportanceForeground(importance);
438 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
439 synchronized (mLock) {
440 for (Entry<String, ArrayList<UpdateRecord>> entry
gomo48f1a642017-11-10 20:35:46 -0800441 : mRecordsByProvider.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700442 String provider = entry.getKey();
443 for (UpdateRecord record : entry.getValue()) {
444 if (record.mReceiver.mIdentity.mUid == uid
gomo48f1a642017-11-10 20:35:46 -0800445 && record.mIsForegroundUid != foreground) {
446 if (D) {
447 Log.d(TAG, "request from uid " + uid + " is now "
448 + (foreground ? "foreground" : "background)"));
449 }
Wyatt Rileyf7075e02018-04-12 17:54:26 -0700450 record.updateForeground(foreground);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700451
452 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
453 affectedProviders.add(provider);
454 }
455 }
456 }
457 }
458 for (String provider : affectedProviders) {
459 applyRequirementsLocked(provider);
460 }
461
Wyatt Riley11cc7492018-01-17 08:48:27 -0800462 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700463 if (entry.getValue().mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800464 if (D) {
465 Log.d(TAG, "gnss measurements listener from uid " + uid
466 + " is now " + (foreground ? "foreground" : "background)"));
467 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700468 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800469 mGnssMeasurementsProvider.addListener(
470 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700471 } else {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800472 mGnssMeasurementsProvider.removeListener(
473 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700474 }
475 }
476 }
477
Wyatt Riley11cc7492018-01-17 08:48:27 -0800478 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700479 if (entry.getValue().mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800480 if (D) {
481 Log.d(TAG, "gnss navigation message listener from uid "
482 + uid + " is now "
483 + (foreground ? "foreground" : "background)"));
484 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700485 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800486 mGnssNavigationMessageProvider.addListener(
487 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700488 } else {
Wyatt Riley11cc7492018-01-17 08:48:27 -0800489 mGnssNavigationMessageProvider.removeListener(
490 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700491 }
492 }
493 }
494 }
495 }
496
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800497 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700498 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800499 }
500
Amith Yamasanib27528d2014-06-05 15:02:10 -0700501 /**
destradaab9026982015-08-27 17:34:54 -0700502 * Provides a way for components held by the {@link LocationManagerService} to clean-up
503 * gracefully on system's shutdown.
504 *
505 * NOTES:
506 * 1) Only provides a chance to clean-up on an opt-in basis. This guarantees back-compat
507 * support for components that do not wish to handle such event.
508 */
509 private void shutdownComponents() {
gomo48f1a642017-11-10 20:35:46 -0800510 if (D) Log.d(TAG, "Shutting down components...");
destradaab9026982015-08-27 17:34:54 -0700511
512 LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
513 if (gpsProvider != null && gpsProvider.isEnabled()) {
514 gpsProvider.disable();
515 }
destradaab9026982015-08-27 17:34:54 -0700516 }
517
518 /**
Amith Yamasanib27528d2014-06-05 15:02:10 -0700519 * Makes a list of userids that are related to the current user. This is
520 * relevant when using managed profiles. Otherwise the list only contains
521 * the current user.
522 *
523 * @param currentUserId the current user, who might have an alter-ego.
524 */
525 void updateUserProfiles(int currentUserId) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700526 int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700527 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700528 mCurrentUserProfiles = profileIds;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700529 }
530 }
531
532 /**
533 * Checks if the specified userId matches any of the current foreground
534 * users stored in mCurrentUserProfiles.
535 */
536 private boolean isCurrentProfile(int userId) {
537 synchronized (mLock) {
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -0700538 return ArrayUtils.contains(mCurrentUserProfiles, userId);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700539 }
540 }
541
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500542 private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
543 PackageManager pm = mContext.getPackageManager();
544 String systemPackageName = mContext.getPackageName();
545 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
546
547 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
548 new Intent(FUSED_LOCATION_SERVICE_ACTION),
549 PackageManager.GET_META_DATA, mCurrentUserId);
550 for (ResolveInfo rInfo : rInfos) {
551 String packageName = rInfo.serviceInfo.packageName;
552
553 // Check that the signature is in the list of supported sigs. If it's not in
554 // this list the standard provider binding logic won't bind to it.
555 try {
556 PackageInfo pInfo;
557 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
558 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
559 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
560 ", but has wrong signature, ignoring");
561 continue;
562 }
563 } catch (NameNotFoundException e) {
564 Log.e(TAG, "missing package: " + packageName);
565 continue;
566 }
567
568 // Get the version info
569 if (rInfo.serviceInfo.metaData == null) {
570 Log.w(TAG, "Found fused provider without metadata: " + packageName);
571 continue;
572 }
573
574 int version = rInfo.serviceInfo.metaData.getInt(
575 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
576 if (version == 0) {
577 // This should be the fallback fused location provider.
578
579 // Make sure it's in the system partition.
580 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
581 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
582 continue;
583 }
584
585 // Check that the fallback is signed the same as the OS
586 // as a proxy for coreApp="true"
587 if (pm.checkSignatures(systemPackageName, packageName)
588 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800589 if (D) {
590 Log.d(TAG, "Fallback candidate not signed the same as system: "
591 + packageName);
592 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500593 continue;
594 }
595
596 // Found a valid fallback.
597 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
598 return;
599 } else {
600 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
601 }
602 }
603
604 throw new IllegalStateException("Unable to find a fused location provider that is in the "
605 + "system partition with version 0 and signed with the platform certificate. "
606 + "Such a package is needed to provide a default fused location provider in the "
607 + "event that no other fused location provider has been installed or is currently "
608 + "available. For example, coreOnly boot mode when decrypting the data "
609 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
610 }
611
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700612 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700613 // create a passive location provider, which is always enabled
614 PassiveProvider passiveProvider = new PassiveProvider(this);
615 addProviderLocked(passiveProvider);
616 mEnabledProviders.add(passiveProvider.getName());
617 mPassiveProvider = passiveProvider;
618
Lifu Tang30f95a72016-01-07 23:20:38 -0800619 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700620 // Create a gps location provider
Lifu Tang30f95a72016-01-07 23:20:38 -0800621 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
Wei Liu5241a4c2015-05-11 14:00:36 -0700622 mLocationHandler.getLooper());
Lifu Tang9363b942016-02-16 18:07:00 -0800623 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800624 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700625 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800626 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
627 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
628 addProviderLocked(gnssProvider);
629 mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
Lifu Tang818aa2c2016-02-01 01:52:00 -0800630 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
631 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800632 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700633 }
634
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700635 /*
636 Load package name(s) containing location provider support.
637 These packages can contain services implementing location providers:
638 Geocoder Provider, Network Location Provider, and
639 Fused Location Provider. They will each be searched for
640 service components implementing these providers.
641 The location framework also has support for installation
642 of new location providers at run-time. The new package does not
643 have to be explicitly listed here, however it must have a signature
644 that matches the signature of at least one package on this list.
645 */
646 Resources resources = mContext.getResources();
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800647 ArrayList<String> providerPackageNames = new ArrayList<>();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500648 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700649 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800650 if (D) {
651 Log.d(TAG, "certificates for location providers pulled from: " +
652 Arrays.toString(pkgs));
653 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500654 if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
655
656 ensureFallbackFusedProviderPresentLocked(providerPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700657
658 // bind to network provider
659 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
660 mContext,
661 LocationManager.NETWORK_PROVIDER,
662 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700663 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
664 com.android.internal.R.string.config_networkLocationProviderPackageName,
665 com.android.internal.R.array.config_locationProviderPackageNames,
666 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700667 if (networkProvider != null) {
668 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
669 mProxyProviders.add(networkProvider);
670 addProviderLocked(networkProvider);
671 } else {
gomo48f1a642017-11-10 20:35:46 -0800672 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700673 }
674
675 // bind to fused provider
676 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
677 mContext,
678 LocationManager.FUSED_PROVIDER,
679 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700680 com.android.internal.R.bool.config_enableFusedLocationOverlay,
681 com.android.internal.R.string.config_fusedLocationProviderPackageName,
682 com.android.internal.R.array.config_locationProviderPackageNames,
683 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700684 if (fusedLocationProvider != null) {
685 addProviderLocked(fusedLocationProvider);
686 mProxyProviders.add(fusedLocationProvider);
687 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700688 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700689 } else {
690 Slog.e(TAG, "no fused location provider found",
691 new IllegalStateException("Location service needs a fused location provider"));
692 }
693
694 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700695 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
696 com.android.internal.R.bool.config_enableGeocoderOverlay,
697 com.android.internal.R.string.config_geocoderProviderPackageName,
698 com.android.internal.R.array.config_locationProviderPackageNames,
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800699 mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700700 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800701 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700702 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700703
destradaaf9a274c2014-07-25 15:11:56 -0700704 // bind to geofence provider
705 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800706 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700707 com.android.internal.R.string.config_geofenceProviderPackageName,
708 com.android.internal.R.array.config_locationProviderPackageNames,
709 mLocationHandler,
Wei Liu5241a4c2015-05-11 14:00:36 -0700710 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900711 null);
destradaaf9a274c2014-07-25 15:11:56 -0700712 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800713 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700714 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900715
destradaa6e2fe752015-06-23 17:25:53 -0700716 // bind to hardware activity recognition
717 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
718 ActivityRecognitionHardware activityRecognitionHardware = null;
719 if (activityRecognitionHardwareIsSupported) {
720 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700721 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700722 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700723 }
destradaa6e2fe752015-06-23 17:25:53 -0700724 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
725 mContext,
726 mLocationHandler,
727 activityRecognitionHardwareIsSupported,
728 activityRecognitionHardware,
729 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
730 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
731 com.android.internal.R.array.config_locationProviderPackageNames);
732 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700733 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700734 }
destradaaa4fa3b52014-07-09 10:46:39 -0700735
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900736 String[] testProviderStrings = resources.getStringArray(
737 com.android.internal.R.array.config_testLocationProviders);
738 for (String testProviderString : testProviderStrings) {
739 String fragments[] = testProviderString.split(",");
740 String name = fragments[0].trim();
741 if (mProvidersByName.get(name) != null) {
742 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
743 }
744 ProviderProperties properties = new ProviderProperties(
745 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
746 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
747 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
748 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
749 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
750 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
751 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
752 Integer.parseInt(fragments[8]) /* powerRequirement */,
753 Integer.parseInt(fragments[9]) /* accuracy */);
754 addTestProviderLocked(name, properties);
755 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700756 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700757
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700759 * Called when the device's active user changes.
gomo48f1a642017-11-10 20:35:46 -0800760 *
Victoria Lease38389b62012-09-30 11:44:22 -0700761 * @param userId the new active user's UserId
762 */
763 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800764 if (mCurrentUserId == userId) {
765 return;
766 }
Victoria Lease83762d22012-10-03 13:51:17 -0700767 mBlacklist.switchUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800768 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
Victoria Lease38389b62012-09-30 11:44:22 -0700769 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700770 mLastLocation.clear();
David Christie1b9b7b12013-04-15 15:31:11 -0700771 mLastLocationCoarseInterval.clear();
Victoria Leaseb711d572012-10-02 13:14:11 -0700772 for (LocationProviderInterface p : mProviders) {
Amith Yamasanib27528d2014-06-05 15:02:10 -0700773 updateProviderListenersLocked(p.getName(), false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700774 }
Victoria Lease38389b62012-09-30 11:44:22 -0700775 mCurrentUserId = userId;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700776 updateUserProfiles(userId);
Victoria Leaseb711d572012-10-02 13:14:11 -0700777 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700778 }
779 }
780
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800781 private static final class Identity {
782 final int mUid;
783 final int mPid;
784 final String mPackageName;
785
786 Identity(int uid, int pid, String packageName) {
787 mUid = uid;
788 mPid = pid;
789 mPackageName = packageName;
790 }
791 }
792
Victoria Lease38389b62012-09-30 11:44:22 -0700793 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
795 * location updates.
796 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700797 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -0700798 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800799 final Identity mIdentity;
Victoria Lease37425c32012-10-16 16:08:48 -0700800 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 final ILocationListener mListener;
803 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700804 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
David Christie40e57822013-07-30 11:36:48 -0700805 final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700807
gomo48f1a642017-11-10 20:35:46 -0800808 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700809
David Christie0b837452013-07-29 16:02:13 -0700810 // True if app ops has started monitoring this receiver for locations.
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700811 boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700812 // True if app ops has started monitoring this receiver for high power (gps) locations.
813 boolean mOpHighPowerMonitoring;
Mike Lockwood48f17512009-04-23 09:12:08 -0700814 int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700815 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700817 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700818 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700821 if (listener != null) {
822 mKey = listener.asBinder();
823 } else {
824 mKey = intent;
825 }
Victoria Lease37425c32012-10-16 16:08:48 -0700826 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800827 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +0000828 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -0700829 workSource = null;
830 }
831 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700832 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700833
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700834 updateMonitoring(true);
835
Victoria Lease0aa28602013-05-29 15:28:26 -0700836 // construct/configure wakelock
837 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700838 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800839 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -0700840 }
841 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -0700842
843 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
844 // only need to release it once.
845 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 }
847
848 @Override
849 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800850 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 }
852
853 @Override
854 public int hashCode() {
855 return mKey.hashCode();
856 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400857
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 @Override
859 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700860 StringBuilder s = new StringBuilder();
861 s.append("Reciever[");
862 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700864 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700866 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700868 for (String p : mUpdateRecords.keySet()) {
869 s.append(" ").append(mUpdateRecords.get(p).toString());
870 }
Wei Wangdd070f22018-06-21 11:29:40 -0700871 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700872 s.append("]");
873 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 }
875
David Christie15b31912013-08-13 15:54:32 -0700876 /**
877 * Update AppOp monitoring for this receiver.
878 *
879 * @param allow If true receiver is currently active, if false it's been removed.
880 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700881 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -0700882 if (mHideFromAppOps) {
883 return;
884 }
885
David Christie15b31912013-08-13 15:54:32 -0700886 boolean requestingLocation = false;
887 boolean requestingHighPowerLocation = false;
888 if (allow) {
889 // See if receiver has any enabled update records. Also note if any update records
890 // are high power (has a high power provider with an interval under a threshold).
891 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
892 if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
893 requestingLocation = true;
894 LocationProviderInterface locationProvider
David Christie2ff96af2014-01-30 16:09:37 -0800895 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -0700896 ProviderProperties properties = locationProvider != null
897 ? locationProvider.getProperties() : null;
898 if (properties != null
899 && properties.mPowerRequirement == Criteria.POWER_HIGH
900 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
901 requestingHighPowerLocation = true;
902 break;
903 }
904 }
905 }
906 }
907
David Christie0b837452013-07-29 16:02:13 -0700908 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -0700909 mOpMonitoring = updateMonitoring(
910 requestingLocation,
911 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700912 AppOpsManager.OP_MONITOR_LOCATION);
913
914 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -0700915 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -0700916 mOpHighPowerMonitoring = updateMonitoring(
917 requestingHighPowerLocation,
918 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -0700919 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -0700920 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -0700921 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -0700922 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
923 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
924 }
David Christie0b837452013-07-29 16:02:13 -0700925 }
926
927 /**
928 * Update AppOps monitoring for a single location request and op type.
929 *
gomo48f1a642017-11-10 20:35:46 -0800930 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -0700931 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -0800932 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -0700933 * @return True if monitoring is on for this request/op after updating.
934 */
935 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
936 int op) {
937 if (!currentlyMonitoring) {
938 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800939 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -0700940 == AppOpsManager.MODE_ALLOWED;
941 }
942 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800943 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -0700944 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -0700945 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800946 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -0700947 return false;
948 }
949 }
950
951 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700952 }
953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 public boolean isListener() {
955 return mListener != null;
956 }
957
958 public boolean isPendingIntent() {
959 return mPendingIntent != null;
960 }
961
962 public ILocationListener getListener() {
963 if (mListener != null) {
964 return mListener;
965 }
966 throw new IllegalStateException("Request for non-existent listener");
967 }
968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
970 if (mListener != null) {
971 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700972 synchronized (this) {
973 // synchronize to ensure incrementPendingBroadcastsLocked()
974 // is called before decrementPendingBroadcasts()
975 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700976 // call this after broadcasting so we do not increment
977 // if we throw an exeption.
978 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700979 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 } catch (RemoteException e) {
981 return false;
982 }
983 } else {
984 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -0800985 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
987 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700988 synchronized (this) {
989 // synchronize to ensure incrementPendingBroadcastsLocked()
990 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700991 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -0700992 getResolutionPermission(mAllowedResolutionLevel),
993 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -0700994 // call this after broadcasting so we do not increment
995 // if we throw an exeption.
996 incrementPendingBroadcastsLocked();
997 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 } catch (PendingIntent.CanceledException e) {
999 return false;
1000 }
1001 }
1002 return true;
1003 }
1004
1005 public boolean callLocationChangedLocked(Location location) {
1006 if (mListener != null) {
1007 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001008 synchronized (this) {
1009 // synchronize to ensure incrementPendingBroadcastsLocked()
1010 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001011 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001012 // call this after broadcasting so we do not increment
1013 // if we throw an exeption.
1014 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001015 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016 } catch (RemoteException e) {
1017 return false;
1018 }
1019 } else {
1020 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001021 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1022 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001024 synchronized (this) {
1025 // synchronize to ensure incrementPendingBroadcastsLocked()
1026 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001027 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001028 getResolutionPermission(mAllowedResolutionLevel),
1029 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001030 // call this after broadcasting so we do not increment
1031 // if we throw an exeption.
1032 incrementPendingBroadcastsLocked();
1033 }
1034 } catch (PendingIntent.CanceledException e) {
1035 return false;
1036 }
1037 }
1038 return true;
1039 }
1040
1041 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001042 // First update AppOp monitoring.
1043 // An app may get/lose location access as providers are enabled/disabled.
1044 updateMonitoring(true);
1045
Mike Lockwood48f17512009-04-23 09:12:08 -07001046 if (mListener != null) {
1047 try {
1048 synchronized (this) {
1049 // synchronize to ensure incrementPendingBroadcastsLocked()
1050 // is called before decrementPendingBroadcasts()
1051 if (enabled) {
1052 mListener.onProviderEnabled(provider);
1053 } else {
1054 mListener.onProviderDisabled(provider);
1055 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001056 // call this after broadcasting so we do not increment
1057 // if we throw an exeption.
1058 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001059 }
1060 } catch (RemoteException e) {
1061 return false;
1062 }
1063 } else {
1064 Intent providerIntent = new Intent();
1065 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1066 try {
1067 synchronized (this) {
1068 // synchronize to ensure incrementPendingBroadcastsLocked()
1069 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001070 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001071 getResolutionPermission(mAllowedResolutionLevel),
1072 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001073 // call this after broadcasting so we do not increment
1074 // if we throw an exeption.
1075 incrementPendingBroadcastsLocked();
1076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 } catch (PendingIntent.CanceledException e) {
1078 return false;
1079 }
1080 }
1081 return true;
1082 }
1083
Nick Pellyf1be6862012-05-15 10:53:42 -07001084 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001086 if (D) Log.d(TAG, "Location listener died");
1087
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001088 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 removeUpdatesLocked(this);
1090 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001091 synchronized (this) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001092 clearPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001093 }
1094 }
1095
Nick Pellye0fd6932012-07-11 10:26:13 -07001096 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001097 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1098 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001099 synchronized (this) {
1100 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001101 }
1102 }
1103
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001104 // this must be called while synchronized by caller in a synchronized block
1105 // containing the sending of the broadcaset
1106 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001107 mPendingBroadcasts++;
1108 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001109 }
1110
1111 private void decrementPendingBroadcastsLocked() {
1112 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001113 if (mWakeLock.isHeld()) {
1114 mWakeLock.release();
1115 }
1116 }
1117 }
1118
1119 public void clearPendingBroadcastsLocked() {
1120 if (mPendingBroadcasts > 0) {
1121 mPendingBroadcasts = 0;
1122 if (mWakeLock.isHeld()) {
1123 mWakeLock.release();
1124 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001125 }
1126 }
1127 }
1128
Nick Pellye0fd6932012-07-11 10:26:13 -07001129 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001130 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001131 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001132 //the receiver list if it is not found. If it is not found then the
1133 //LocationListener was removed when it had a pending broadcast and should
1134 //not be added back.
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001135 synchronized (mLock) {
1136 IBinder binder = listener.asBinder();
1137 Receiver receiver = mReceivers.get(binder);
1138 if (receiver != null) {
1139 synchronized (receiver) {
1140 // so wakelock calls will succeed
1141 long identity = Binder.clearCallingIdentity();
1142 receiver.decrementPendingBroadcastsLocked();
1143 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -08001144 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001145 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 }
1147 }
1148
Lifu Tang82f893d2016-01-21 18:15:33 -08001149 /**
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001150 * Returns the year of the GNSS hardware.
Lifu Tang82f893d2016-01-21 18:15:33 -08001151 */
1152 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001153 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001154 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001155 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001156 } else {
1157 return 0;
1158 }
1159 }
1160
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001161
1162 /**
1163 * Returns the model name of the GNSS hardware.
1164 */
1165 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001166 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001167 public String getGnssHardwareModelName() {
1168 if (mGnssSystemInfoProvider != null) {
1169 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1170 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001171 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001172 }
1173 }
1174
Wyatt Rileycf879db2017-01-12 13:57:38 -08001175 /**
1176 * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
1177 * (try to) access GNSS information at this layer.
1178 */
1179 private boolean hasGnssPermissions(String packageName) {
1180 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1181 checkResolutionLevelIsSufficientForProviderUse(
1182 allowedResolutionLevel,
1183 LocationManager.GPS_PROVIDER);
1184
1185 int pid = Binder.getCallingPid();
1186 int uid = Binder.getCallingUid();
1187 long identity = Binder.clearCallingIdentity();
1188 boolean hasLocationAccess;
1189 try {
1190 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1191 } finally {
1192 Binder.restoreCallingIdentity(identity);
1193 }
1194
1195 return hasLocationAccess;
1196 }
1197
1198 /**
1199 * Returns the GNSS batching size, if available.
1200 */
1201 @Override
1202 public int getGnssBatchSize(String packageName) {
1203 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1204 "Location Hardware permission not granted to access hardware batching");
1205
1206 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001207 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001208 } else {
1209 return 0;
1210 }
1211 }
1212
1213 /**
1214 * Adds a callback for GNSS Batching events, if permissions allow, which are transported
1215 * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
1216 */
1217 @Override
1218 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1219 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1220 "Location Hardware permission not granted to access hardware batching");
1221
1222 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1223 return false;
1224 }
1225
1226 mGnssBatchingCallback = callback;
1227 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1228 try {
1229 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1230 } catch (RemoteException e) {
1231 // if the remote process registering the listener is already dead, just swallow the
1232 // exception and return
1233 Log.e(TAG, "Remote listener already died.", e);
1234 return false;
1235 }
1236
1237 return true;
1238 }
1239
1240 private class LinkedCallback implements IBinder.DeathRecipient {
1241 private final IBatchedLocationCallback mCallback;
1242
1243 public LinkedCallback(@NonNull IBatchedLocationCallback callback) {
1244 mCallback = callback;
1245 }
1246
1247 @NonNull
1248 public IBatchedLocationCallback getUnderlyingListener() {
1249 return mCallback;
1250 }
1251
1252 @Override
1253 public void binderDied() {
1254 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1255 stopGnssBatch();
1256 removeGnssBatchingCallback();
1257 }
1258 }
1259
1260 /**
1261 * Removes callback for GNSS batching
1262 */
1263 @Override
1264 public void removeGnssBatchingCallback() {
1265 try {
1266 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1267 0 /* flags */);
1268 } catch (NoSuchElementException e) {
1269 // if the death callback isn't connected (it should be...), log error, swallow the
1270 // exception and return
1271 Log.e(TAG, "Couldn't unlink death callback.", e);
1272 }
1273 mGnssBatchingCallback = null;
1274 mGnssBatchingDeathCallback = null;
1275 }
1276
1277
1278 /**
1279 * Starts GNSS batching, if available.
1280 */
1281 @Override
1282 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1283 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1284 "Location Hardware permission not granted to access hardware batching");
1285
1286 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1287 return false;
1288 }
1289
1290 if (mGnssBatchingInProgress) {
1291 // Current design does not expect multiple starts to be called repeatedly
1292 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1293 // Try to clean up anyway, and continue
1294 stopGnssBatch();
1295 }
1296
1297 mGnssBatchingInProgress = true;
1298 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1299 }
1300
1301 /**
1302 * Flushes a GNSS batch in progress
1303 */
1304 @Override
1305 public void flushGnssBatch(String packageName) {
1306 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1307 "Location Hardware permission not granted to access hardware batching");
1308
1309 if (!hasGnssPermissions(packageName)) {
1310 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1311 return;
1312 }
1313
1314 if (!mGnssBatchingInProgress) {
1315 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1316 }
1317
1318 if (mGnssBatchingProvider != null) {
gomo48f1a642017-11-10 20:35:46 -08001319 mGnssBatchingProvider.flush();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001320 }
1321 }
1322
1323 /**
1324 * Stops GNSS batching
1325 */
1326 @Override
1327 public boolean stopGnssBatch() {
1328 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1329 "Location Hardware permission not granted to access hardware batching");
1330
1331 if (mGnssBatchingProvider != null) {
1332 mGnssBatchingInProgress = false;
1333 return mGnssBatchingProvider.stop();
gomo48f1a642017-11-10 20:35:46 -08001334 } else {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001335 return false;
1336 }
1337 }
1338
1339 @Override
1340 public void reportLocationBatch(List<Location> locations) {
1341 checkCallerIsProvider();
1342
1343 // Currently used only for GNSS locations - update permissions check if changed
1344 if (isAllowedByCurrentUserSettingsLocked(LocationManager.GPS_PROVIDER)) {
1345 if (mGnssBatchingCallback == null) {
1346 Slog.e(TAG, "reportLocationBatch() called without active Callback");
1347 return;
1348 }
1349 try {
1350 mGnssBatchingCallback.onLocationBatch(locations);
1351 } catch (RemoteException e) {
1352 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1353 }
1354 } else {
1355 Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
1356 }
1357 }
1358
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001359 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001360 mProviders.add(provider);
1361 mProvidersByName.put(provider.getName(), provider);
1362 }
1363
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001364 private void removeProviderLocked(LocationProviderInterface provider) {
1365 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001366 mProviders.remove(provider);
1367 mProvidersByName.remove(provider.getName());
1368 }
1369
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001370 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001371 * Returns "true" if access to the specified location provider is allowed by the current
1372 * user's settings. Access to all location providers is forbidden to non-location-provider
1373 * processes belonging to background users.
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001374 *
1375 * @param provider the name of the location provider
Victoria Lease03cdd3d2013-02-01 15:15:54 -08001376 */
Victoria Lease09eeaec2013-02-05 11:34:13 -08001377 private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
Maggie2a9409e2018-03-21 11:47:28 -07001378 return isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 }
1380
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001381 /**
Victoria Lease09eeaec2013-02-05 11:34:13 -08001382 * Returns "true" if access to the specified location provider is allowed by the specified
1383 * user's settings. Access to all location providers is forbidden to non-location-provider
1384 * processes belonging to background users.
1385 *
1386 * @param provider the name of the location provider
Maggie2a9409e2018-03-21 11:47:28 -07001387 * @param userId the user id to query
Victoria Lease09eeaec2013-02-05 11:34:13 -08001388 */
Maggie2a9409e2018-03-21 11:47:28 -07001389 private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
1390 if (mEnabledProviders.contains(provider)) {
1391 return true;
1392 }
1393 if (mDisabledProviders.contains(provider)) {
1394 return false;
1395 }
1396 return isLocationProviderEnabledForUser(provider, userId);
1397 }
1398
1399
1400 /**
1401 * Returns "true" if access to the specified location provider is allowed by the specified
1402 * user's settings. Access to all location providers is forbidden to non-location-provider
1403 * processes belonging to background users.
1404 *
1405 * @param provider the name of the location provider
1406 * @param uid the requestor's UID
1407 * @param userId the user id to query
1408 */
1409 private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001410 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001411 return false;
1412 }
Maggie2a9409e2018-03-21 11:47:28 -07001413 return isAllowedByUserSettingsLockedForUser(provider, userId);
Victoria Lease09eeaec2013-02-05 11:34:13 -08001414 }
1415
1416 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001417 * Returns the permission string associated with the specified resolution level.
1418 *
1419 * @param resolutionLevel the resolution level
1420 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001421 */
Victoria Lease37425c32012-10-16 16:08:48 -07001422 private String getResolutionPermission(int resolutionLevel) {
1423 switch (resolutionLevel) {
1424 case RESOLUTION_LEVEL_FINE:
1425 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1426 case RESOLUTION_LEVEL_COARSE:
1427 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1428 default:
1429 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001431 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001432
Victoria Leaseda479c52012-10-15 15:24:16 -07001433 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001434 * Returns the resolution level allowed to the given PID/UID pair.
1435 *
1436 * @param pid the PID
1437 * @param uid the UID
1438 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -07001439 */
Victoria Lease37425c32012-10-16 16:08:48 -07001440 private int getAllowedResolutionLevel(int pid, int uid) {
1441 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001442 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001443 return RESOLUTION_LEVEL_FINE;
1444 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001445 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001446 return RESOLUTION_LEVEL_COARSE;
1447 } else {
1448 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001449 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001450 }
1451
1452 /**
Victoria Lease37425c32012-10-16 16:08:48 -07001453 * Returns the resolution level allowed to the caller
1454 *
1455 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -07001456 */
Victoria Lease37425c32012-10-16 16:08:48 -07001457 private int getCallerAllowedResolutionLevel() {
1458 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1459 }
1460
1461 /**
1462 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1463 *
1464 * @param allowedResolutionLevel resolution level allowed to caller
1465 */
1466 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1467 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001468 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 }
1471
Victoria Lease37425c32012-10-16 16:08:48 -07001472 /**
1473 * Return the minimum resolution level required to use the specified location provider.
1474 *
1475 * @param provider the name of the location provider
1476 * @return minimum resolution level required for provider
1477 */
1478 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001479 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1480 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1481 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001482 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001483 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1484 LocationManager.FUSED_PROVIDER.equals(provider)) {
1485 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001486 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001487 } else {
1488 // mock providers
1489 LocationProviderInterface lp = mMockProviders.get(provider);
1490 if (lp != null) {
1491 ProviderProperties properties = lp.getProperties();
1492 if (properties != null) {
1493 if (properties.mRequiresSatellite) {
1494 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001495 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001496 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1497 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001498 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001499 }
1500 }
1501 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001502 }
Victoria Lease37425c32012-10-16 16:08:48 -07001503 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001504 }
1505
Victoria Lease37425c32012-10-16 16:08:48 -07001506 /**
1507 * Throw SecurityException if specified resolution level is insufficient to use the named
1508 * location provider.
1509 *
1510 * @param allowedResolutionLevel resolution level allowed to caller
gomo48f1a642017-11-10 20:35:46 -08001511 * @param providerName the name of the location provider
Victoria Lease37425c32012-10-16 16:08:48 -07001512 */
1513 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1514 String providerName) {
1515 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1516 if (allowedResolutionLevel < requiredResolutionLevel) {
1517 switch (requiredResolutionLevel) {
1518 case RESOLUTION_LEVEL_FINE:
1519 throw new SecurityException("\"" + providerName + "\" location provider " +
1520 "requires ACCESS_FINE_LOCATION permission.");
1521 case RESOLUTION_LEVEL_COARSE:
1522 throw new SecurityException("\"" + providerName + "\" location provider " +
1523 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1524 default:
1525 throw new SecurityException("Insufficient permission for \"" + providerName +
1526 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001527 }
1528 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001529 }
1530
David Christie82edc9b2013-07-19 11:31:42 -07001531 /**
1532 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1533 * for battery).
1534 */
David Christie40e57822013-07-30 11:36:48 -07001535 private void checkDeviceStatsAllowed() {
David Christie82edc9b2013-07-19 11:31:42 -07001536 mContext.enforceCallingOrSelfPermission(
1537 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1538 }
1539
David Christie40e57822013-07-30 11:36:48 -07001540 private void checkUpdateAppOpsAllowed() {
1541 mContext.enforceCallingOrSelfPermission(
1542 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1543 }
1544
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001545 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001546 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1547 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001548 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001549 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001550 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001551 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001552 }
1553 return -1;
1554 }
1555
Wei Wangb86334f2018-07-03 16:33:24 -07001556 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
1557 switch(allowedResolutionLevel) {
1558 case RESOLUTION_LEVEL_COARSE:
1559 return AppOpsManager.OPSTR_COARSE_LOCATION;
1560 case RESOLUTION_LEVEL_FINE:
1561 return AppOpsManager.OPSTR_FINE_LOCATION;
1562 case RESOLUTION_LEVEL_NONE:
1563 // The client is not allowed to get any location, so both FINE and COARSE ops will
1564 // be denied. Pick the most restrictive one to be safe.
1565 return AppOpsManager.OPSTR_FINE_LOCATION;
1566 default:
1567 // Use the most restrictive ops if not sure.
1568 return AppOpsManager.OPSTR_FINE_LOCATION;
1569 }
1570 }
1571
David Christieb870dbf2015-06-22 12:42:53 -07001572 boolean reportLocationAccessNoThrow(
1573 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001574 int op = resolutionLevelToOp(allowedResolutionLevel);
1575 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001576 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1577 return false;
1578 }
1579 }
David Christieb870dbf2015-06-22 12:42:53 -07001580
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001581 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001582 }
1583
David Christieb870dbf2015-06-22 12:42:53 -07001584 boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001585 int op = resolutionLevelToOp(allowedResolutionLevel);
1586 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001587 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001588 return false;
1589 }
1590 }
David Christieb870dbf2015-06-22 12:42:53 -07001591
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001592 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001593 }
1594
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001595 /**
Maggie91e630c2018-01-24 17:31:46 -08001596 * Returns all providers by name, including passive and the ones that are not permitted to
1597 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001598 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001599 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 public List<String> getAllProviders() {
Maggie91e630c2018-01-24 17:31:46 -08001601 ArrayList<String> out;
1602 synchronized (mLock) {
1603 out = new ArrayList<>(mProviders.size());
1604 for (LocationProviderInterface provider : mProviders) {
1605 String name = provider.getName();
1606 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1607 continue;
1608 }
1609 out.add(name);
1610 }
1611 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001612 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 return out;
1614 }
1615
Mike Lockwood03ca2162010-04-01 08:10:09 -07001616 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001617 * Return all providers by name, that match criteria and are optionally
1618 * enabled.
1619 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001620 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001621 @Override
1622 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001623 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001624 ArrayList<String> out;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001625 int uid = Binder.getCallingUid();
Victoria Lease269518e2012-10-29 08:25:39 -07001626 long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07001627 try {
1628 synchronized (mLock) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001629 out = new ArrayList<>(mProviders.size());
Victoria Leaseb711d572012-10-02 13:14:11 -07001630 for (LocationProviderInterface provider : mProviders) {
1631 String name = provider.getName();
1632 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001633 continue;
1634 }
Victoria Lease37425c32012-10-16 16:08:48 -07001635 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Maggie2a9409e2018-03-21 11:47:28 -07001636 if (enabledOnly
1637 && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001638 continue;
1639 }
1640 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
1641 name, provider.getProperties(), criteria)) {
1642 continue;
1643 }
1644 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001645 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001646 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001647 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001648 } finally {
1649 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001650 }
1651
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001652 if (D) Log.d(TAG, "getProviders()=" + out);
1653 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001654 }
1655
1656 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001657 * Return the name of the best provider given a Criteria object.
1658 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001659 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001660 * has been deprecated as well. So this method now uses
1661 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001662 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001663 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001664 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001665 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001666
1667 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001668 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001669 result = pickBest(providers);
1670 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1671 return result;
1672 }
1673 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -07001674 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001675 result = pickBest(providers);
1676 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1677 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001678 }
1679
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001680 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001681 return null;
1682 }
1683
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001684 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -07001685 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001686 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -07001687 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1688 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001689 } else {
1690 return providers.get(0);
1691 }
1692 }
1693
Nick Pellye0fd6932012-07-11 10:26:13 -07001694 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001695 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1696 LocationProviderInterface p = mProvidersByName.get(provider);
1697 if (p == null) {
1698 throw new IllegalArgumentException("provider=" + provider);
1699 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001700
1701 boolean result = LocationProvider.propertiesMeetCriteria(
1702 p.getName(), p.getProperties(), criteria);
1703 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1704 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001705 }
1706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001708 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001709 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001710 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 boolean isEnabled = p.isEnabled();
1712 String name = p.getName();
Victoria Lease09eeaec2013-02-05 11:34:13 -08001713 boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 if (isEnabled && !shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001715 updateProviderListenersLocked(name, false);
David Christieb084fef2013-12-18 14:33:57 -08001716 // If any provider has been disabled, clear all last locations for all providers.
1717 // This is to be on the safe side in case a provider has location derived from
1718 // this disabled provider.
1719 mLastLocation.clear();
1720 mLastLocationCoarseInterval.clear();
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001721 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 } else if (!isEnabled && shouldBeEnabled) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001723 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001724 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001726 }
1727 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001728 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
1729 UserHandle.ALL);
Tom O'Neill40a86c22013-09-03 18:05:13 -07001730 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1731 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 }
1733 }
1734
Amith Yamasanib27528d2014-06-05 15:02:10 -07001735 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 int listeners = 0;
1737
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001738 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001739 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740
1741 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1744 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001745 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001746 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001747 // Sends a notification message to the receiver
1748 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1749 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001750 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001751 }
1752 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001754 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 }
1757 }
1758
1759 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001760 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 removeUpdatesLocked(deadReceivers.get(i));
1762 }
1763 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 if (enabled) {
1766 p.enable();
1767 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001768 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 }
1770 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 }
1774
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001775 private void applyRequirementsLocked(String provider) {
1776 LocationProviderInterface p = mProvidersByName.get(provider);
1777 if (p == null) return;
1778
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001780 WorkSource worksource = new WorkSource();
1781 ProviderRequest providerRequest = new ProviderRequest();
1782
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001783 ContentResolver resolver = mContext.getContentResolver();
1784 long backgroundThrottleInterval = Settings.Global.getLong(
1785 resolver,
1786 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1787 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
gomo48f1a642017-11-10 20:35:46 -08001788 // initialize the low power mode to true and set to false if any of the records requires
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001789
gomo48f1a642017-11-10 20:35:46 -08001790 providerRequest.lowPowerMode = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001792 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001793 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001794 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001795 record.mReceiver.mIdentity.mPid,
1796 record.mReceiver.mIdentity.mUid,
1797 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001798 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001799 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001800 long interval = locationRequest.getInterval();
1801
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001802 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001803 if (!record.mIsForegroundUid) {
1804 interval = Math.max(interval, backgroundThrottleInterval);
1805 }
1806 if (interval != locationRequest.getInterval()) {
1807 locationRequest = new LocationRequest(locationRequest);
1808 locationRequest.setInterval(interval);
1809 }
1810 }
1811
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001812 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001813 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08001814 if (!locationRequest.isLowPowerMode()) {
1815 providerRequest.lowPowerMode = false;
1816 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001817 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001818 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001819 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001820 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001821 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001822 }
1823 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001824
1825 if (providerRequest.reportLocation) {
1826 // calculate who to blame for power
1827 // This is somewhat arbitrary. We pick a threshold interval
1828 // that is slightly higher that the minimum interval, and
1829 // spread the blame across all applications with a request
1830 // under that threshold.
1831 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1832 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001833 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001834 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001835
1836 // Don't assign battery blame for update records whose
1837 // client has no permission to receive location data.
1838 if (!providerRequest.locationRequests.contains(locationRequest)) {
1839 continue;
1840 }
1841
Victoria Leaseb711d572012-10-02 13:14:11 -07001842 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001843 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00001844 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07001845 worksource.add(record.mReceiver.mWorkSource);
1846 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00001847 // Assign blame to caller if there's no WorkSource associated with
1848 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07001849 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001850 record.mReceiver.mIdentity.mUid,
1851 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001852 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001853 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001854 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001855 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 }
1857 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001858
1859 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1860 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 }
1862
Narayan Kamath32684dd2018-01-08 17:32:51 +00001863 /**
1864 * Whether a given {@code WorkSource} associated with a Location request is valid.
1865 */
1866 private static boolean isValidWorkSource(WorkSource workSource) {
1867 if (workSource.size() > 0) {
1868 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
1869 // by tags.
1870 return workSource.getName(0) != null;
1871 } else {
1872 // For now, make sure callers have supplied an attribution tag for use with
1873 // AppOpsManager. This might be relaxed in the future.
1874 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
1875 return workChains != null && !workChains.isEmpty() &&
1876 workChains.get(0).getAttributionTag() != null;
1877 }
1878 }
1879
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001880 @Override
1881 public String[] getBackgroundThrottlingWhitelist() {
1882 synchronized (mLock) {
1883 return mBackgroundThrottlePackageWhitelist.toArray(
gomo48f1a642017-11-10 20:35:46 -08001884 new String[mBackgroundThrottlePackageWhitelist.size()]);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001885 }
1886 }
1887
1888 private void updateBackgroundThrottlingWhitelistLocked() {
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001889 String setting = Settings.Global.getString(
gomo48f1a642017-11-10 20:35:46 -08001890 mContext.getContentResolver(),
1891 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001892 if (setting == null) {
1893 setting = "";
1894 }
1895
1896 mBackgroundThrottlePackageWhitelist.clear();
1897 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08001898 SystemConfig.getInstance().getAllowUnthrottledLocation());
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001899 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08001900 Arrays.asList(setting.split(",")));
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001901 }
1902
Wei Wangdd070f22018-06-21 11:29:40 -07001903 private void updateLastLocationMaxAgeLocked() {
1904 mLastLocationMaxAgeMs =
1905 Settings.Global.getLong(
1906 mContext.getContentResolver(),
1907 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
1908 DEFAULT_LAST_LOCATION_MAX_AGE_MS);
1909 }
1910
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001911 private boolean isThrottlingExemptLocked(Identity identity) {
1912 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001913 return true;
1914 }
1915
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001916 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001917 return true;
1918 }
1919
1920 for (LocationProviderProxy provider : mProxyProviders) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001921 if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001922 return true;
1923 }
1924 }
1925
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001926 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001927 }
1928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 private class UpdateRecord {
1930 final String mProvider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001931 final LocationRequest mRealRequest; // original request from client
1932 LocationRequest mRequest; // possibly throttled version of the request
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001933 final Receiver mReceiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001934 boolean mIsForegroundUid;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001935 Location mLastFixBroadcast;
1936 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937
1938 /**
1939 * Note: must be constructed with lock held.
1940 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001941 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001943 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001944 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001946 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001947 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001948
1949 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1950 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001951 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 mRecordsByProvider.put(provider, records);
1953 }
1954 if (!records.contains(this)) {
1955 records.add(this);
1956 }
David Christie2ff96af2014-01-30 16:09:37 -08001957
1958 // Update statistics for historical location requests by package/provider
1959 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07001960 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
1961 mIsForegroundUid);
1962 }
1963
1964 /**
1965 * Method to be called when record changes foreground/background
1966 */
1967 void updateForeground(boolean isForeground){
1968 mIsForegroundUid = isForeground;
1969 mRequestStatistics.updateForeground(
1970 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 }
1972
1973 /**
David Christie2ff96af2014-01-30 16:09:37 -08001974 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001976 void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001977 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08001978
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001979 // remove from mRecordsByProvider
1980 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
1981 if (globalRecords != null) {
1982 globalRecords.remove(this);
1983 }
1984
1985 if (!removeReceiver) return; // the caller will handle the rest
1986
1987 // remove from Receiver#mUpdateRecords
1988 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
1989 if (receiverRecords != null) {
1990 receiverRecords.remove(this.mProvider);
1991
1992 // and also remove the Receiver if it has no more update records
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001993 if (receiverRecords.size() == 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001994 removeUpdatesLocked(mReceiver);
1995 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001996 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 }
1998
1999 @Override
2000 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002001 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002002 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2003 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002004 + ")" + " " + mRealRequest + " "
2005 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 }
2008
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002009 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002010 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002011 IBinder binder = listener.asBinder();
2012 Receiver receiver = mReceivers.get(binder);
2013 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002014 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2015 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002016 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002017 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002018 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002019 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002020 return null;
2021 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002022 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002023 }
2024 return receiver;
2025 }
2026
David Christie82edc9b2013-07-19 11:31:42 -07002027 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002028 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002029 Receiver receiver = mReceivers.get(intent);
2030 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002031 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2032 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002033 mReceivers.put(intent, receiver);
2034 }
2035 return receiver;
2036 }
2037
Victoria Lease37425c32012-10-16 16:08:48 -07002038 /**
2039 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2040 * and consistency requirements.
2041 *
2042 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002043 * @return a version of request that meets the given resolution and consistency requirements
2044 * @hide
2045 */
gomo48f1a642017-11-10 20:35:46 -08002046 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2047 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002048 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002049 if (!callerHasLocationHardwarePermission) {
2050 // allow setting low power mode only for callers with location hardware permission
2051 sanitizedRequest.setLowPowerMode(false);
2052 }
Victoria Lease37425c32012-10-16 16:08:48 -07002053 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2054 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002055 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002056 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002057 break;
2058 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002059 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002060 break;
2061 }
2062 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002063 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2064 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002065 }
Victoria Lease37425c32012-10-16 16:08:48 -07002066 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2067 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002068 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002069 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002070 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002071 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002072 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002073 }
Victoria Lease37425c32012-10-16 16:08:48 -07002074 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002075 }
2076
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002077 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002078 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002079 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002080 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002081 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002082 String[] packages = mPackageManager.getPackagesForUid(uid);
2083 if (packages == null) {
2084 throw new SecurityException("invalid UID " + uid);
2085 }
2086 for (String pkg : packages) {
2087 if (packageName.equals(pkg)) return;
2088 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002089 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002090 }
2091
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002092 private void checkPendingIntent(PendingIntent intent) {
2093 if (intent == null) {
2094 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002095 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002096 }
2097
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002098 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
David Christie40e57822013-07-30 11:36:48 -07002099 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002100 if (intent == null && listener == null) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002101 throw new IllegalArgumentException("need either listener or intent");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002102 } else if (intent != null && listener != null) {
2103 throw new IllegalArgumentException("cannot register both listener and intent");
2104 } else if (intent != null) {
2105 checkPendingIntent(intent);
David Christie40e57822013-07-30 11:36:48 -07002106 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002107 } else {
David Christie40e57822013-07-30 11:36:48 -07002108 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002109 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07002110 }
2111
Nick Pellye0fd6932012-07-11 10:26:13 -07002112 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002113 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
2114 PendingIntent intent, String packageName) {
2115 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2116 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002117 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2118 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2119 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07002120 WorkSource workSource = request.getWorkSource();
Narayan Kamath32684dd2018-01-08 17:32:51 +00002121 if (workSource != null && !workSource.isEmpty()) {
David Christie40e57822013-07-30 11:36:48 -07002122 checkDeviceStatsAllowed();
2123 }
2124 boolean hideFromAppOps = request.getHideFromAppOps();
2125 if (hideFromAppOps) {
2126 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07002127 }
gomo48f1a642017-11-10 20:35:46 -08002128 boolean callerHasLocationHardwarePermission =
2129 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002130 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002131 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2132 callerHasLocationHardwarePermission);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002133
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002134 final int pid = Binder.getCallingPid();
2135 final int uid = Binder.getCallingUid();
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002136 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 long identity = Binder.clearCallingIdentity();
2138 try {
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002139 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2140 // a location.
David Christieb870dbf2015-06-22 12:42:53 -07002141 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002142
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002143 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002144 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
David Christie40e57822013-07-30 11:36:48 -07002145 packageName, workSource, hideFromAppOps);
Victoria Lease37425c32012-10-16 16:08:48 -07002146 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04002147 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002148 } finally {
2149 Binder.restoreCallingIdentity(identity);
2150 }
2151 }
2152
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002153 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
2154 int pid, int uid, String packageName) {
2155 // Figure out the provider. Either its explicitly request (legacy use cases), or
2156 // use the fused provider
2157 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2158 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002159 if (name == null) {
2160 throw new IllegalArgumentException("provider name must not be null");
2161 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002162
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002163 LocationProviderInterface provider = mProvidersByName.get(name);
2164 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002165 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002166 }
2167
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002168 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002169 if (D) {
2170 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2171 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2172 + (record.mIsForegroundUid ? "foreground" : "background")
2173 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002174 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002175 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002176
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002177 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2178 if (oldRecord != null) {
2179 oldRecord.disposeLocked(false);
2180 }
2181
Maggie2a9409e2018-03-21 11:47:28 -07002182 boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002183 if (isProviderEnabled) {
2184 applyRequirementsLocked(name);
2185 } else {
2186 // Notify the listener that updates are currently disabled
2187 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 }
David Christie0b837452013-07-29 16:02:13 -07002189 // Update the monitoring here just in case multiple location requests were added to the
2190 // same receiver (this request may be high power and the initial might not have been).
2191 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002192 }
2193
Nick Pellye0fd6932012-07-11 10:26:13 -07002194 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002195 public void removeUpdates(ILocationListener listener, PendingIntent intent,
2196 String packageName) {
2197 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002198
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002199 final int pid = Binder.getCallingPid();
2200 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002201
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002202 synchronized (mLock) {
David Christie82edc9b2013-07-19 11:31:42 -07002203 WorkSource workSource = null;
David Christie40e57822013-07-30 11:36:48 -07002204 boolean hideFromAppOps = false;
2205 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
2206 packageName, workSource, hideFromAppOps);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002207
2208 // providers may use public location API's, need to clear identity
2209 long identity = Binder.clearCallingIdentity();
2210 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002211 removeUpdatesLocked(receiver);
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07002212 } finally {
2213 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002214 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 }
2216 }
2217
2218 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002219 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002220
2221 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2222 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2223 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002224 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002225 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002226 }
2227
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002228 receiver.updateMonitoring(false);
2229
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002230 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002231 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002232 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2233 if (oldRecords != null) {
2234 // Call dispose() on the obsolete update records.
2235 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002236 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002237 record.disposeLocked(false);
2238 }
2239 // Accumulate providers
2240 providers.addAll(oldRecords.keySet());
2241 }
2242
2243 // update provider
2244 for (String provider : providers) {
2245 // If provider is already disabled, don't need to do anything
Victoria Lease09eeaec2013-02-05 11:34:13 -08002246 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002247 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002248 }
2249
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002250 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002251 }
2252 }
2253
Dianne Hackbornc2293022013-02-06 23:14:49 -08002254 private void applyAllProviderRequirementsLocked() {
2255 for (LocationProviderInterface p : mProviders) {
2256 // If provider is already disabled, don't need to do anything
Dianne Hackborn64d41d72013-02-07 00:33:31 -08002257 if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
Dianne Hackbornc2293022013-02-06 23:14:49 -08002258 continue;
2259 }
2260
2261 applyRequirementsLocked(p.getName());
2262 }
2263 }
2264
Nick Pellye0fd6932012-07-11 10:26:13 -07002265 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07002266 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002267 if (D) Log.d(TAG, "getLastLocation: " + request);
2268 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002269 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07002270 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002271 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2272 request.getProvider());
2273 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002274
David Christieb870dbf2015-06-22 12:42:53 -07002275 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002276 final int uid = Binder.getCallingUid();
2277 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002278 try {
2279 if (mBlacklist.isBlacklisted(packageName)) {
gomo48f1a642017-11-10 20:35:46 -08002280 if (D) {
2281 Log.d(TAG, "not returning last loc for blacklisted app: " +
2282 packageName);
2283 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002284 return null;
2285 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002286
David Christieb870dbf2015-06-22 12:42:53 -07002287 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002288 if (D) {
2289 Log.d(TAG, "not returning last loc for no op app: " +
2290 packageName);
2291 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002292 return null;
2293 }
2294
Victoria Leaseb711d572012-10-02 13:14:11 -07002295 synchronized (mLock) {
2296 // Figure out the provider. Either its explicitly request (deprecated API's),
2297 // or use the fused provider
2298 String name = request.getProvider();
2299 if (name == null) name = LocationManager.FUSED_PROVIDER;
2300 LocationProviderInterface provider = mProvidersByName.get(name);
2301 if (provider == null) return null;
2302
Maggie2a9409e2018-03-21 11:47:28 -07002303 if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07002304
David Christie1b9b7b12013-04-15 15:31:11 -07002305 Location location;
2306 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2307 // Make sure that an app with coarse permissions can't get frequent location
2308 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2309 location = mLastLocationCoarseInterval.get(name);
2310 } else {
2311 location = mLastLocation.get(name);
2312 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002313 if (location == null) {
2314 return null;
2315 }
Wei Wangdd070f22018-06-21 11:29:40 -07002316
2317 // Don't return stale location to apps with foreground-only location permission.
Wei Wangb86334f2018-07-03 16:33:24 -07002318 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Wei Wangdd070f22018-06-21 11:29:40 -07002319 long locationAgeMs = SystemClock.elapsedRealtime() -
2320 location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2321 if ((locationAgeMs > mLastLocationMaxAgeMs)
2322 && (mAppOps.unsafeCheckOp(op, uid, packageName)
2323 == AppOpsManager.MODE_FOREGROUND)) {
2324 return null;
2325 }
2326
Victoria Lease37425c32012-10-16 16:08:48 -07002327 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
gomo48f1a642017-11-10 20:35:46 -08002328 Location noGPSLocation = location.getExtraLocation(
2329 Location.EXTRA_NO_GPS_LOCATION);
Victoria Leaseb711d572012-10-02 13:14:11 -07002330 if (noGPSLocation != null) {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002331 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
Victoria Leaseb711d572012-10-02 13:14:11 -07002332 }
Victoria Lease37425c32012-10-16 16:08:48 -07002333 } else {
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08002334 return new Location(location);
Victoria Lease09016ab2012-09-16 12:33:15 -07002335 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002336 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002337 return null;
2338 } finally {
2339 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002340 }
2341 }
2342
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002343 /**
2344 * Provides an interface to inject and set the last location if location is not available
2345 * currently.
2346 *
2347 * This helps in cases where the product (Cars for example) has saved the last known location
2348 * before powering off. This interface lets the client inject the saved location while the GPS
2349 * chipset is getting its first fix, there by improving user experience.
2350 *
2351 * @param location - Location object to inject
2352 * @return true if update was successful, false if not
2353 */
2354 @Override
2355 public boolean injectLocation(Location location) {
2356 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2357 "Location Hardware permission not granted to inject location");
2358 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2359 "Access Fine Location permission not granted to inject Location");
2360
2361 if (location == null) {
2362 if (D) {
2363 Log.d(TAG, "injectLocation(): called with null location");
2364 }
2365 return false;
2366 }
2367 LocationProviderInterface p = null;
2368 String provider = location.getProvider();
2369 if (provider != null) {
2370 p = mProvidersByName.get(provider);
2371 }
2372 if (p == null) {
2373 if (D) {
2374 Log.d(TAG, "injectLocation(): unknown provider");
2375 }
2376 return false;
2377 }
2378 synchronized (mLock) {
2379 if (!isAllowedByCurrentUserSettingsLocked(provider)) {
2380 if (D) {
2381 Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
2382 }
2383 return false;
2384 } else {
2385 // NOTE: If last location is already available, location is not injected. If
2386 // provider's normal source (like a GPS chipset) have already provided an output,
2387 // there is no need to inject this location.
2388 if (mLastLocation.get(provider) == null) {
2389 updateLastLocationLocked(location, provider);
2390 } else {
2391 if (D) {
2392 Log.d(TAG, "injectLocation(): Location exists. Not updating");
2393 }
2394 return false;
2395 }
2396 }
2397 }
2398 return true;
2399 }
2400
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002401 @Override
2402 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2403 String packageName) {
2404 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002405 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2406 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002407 checkPendingIntent(intent);
2408 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002409 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2410 request.getProvider());
gomo48f1a642017-11-10 20:35:46 -08002411 // Require that caller can manage given document
2412 boolean callerHasLocationHardwarePermission =
2413 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002414 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002415 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2416 callerHasLocationHardwarePermission);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002417
Victoria Lease37425c32012-10-16 16:08:48 -07002418 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002419
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002420 // geo-fence manager uses the public location API, need to clear identity
2421 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07002422 // TODO: http://b/23822629
2423 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08002424 // temporary measure until geofences work for secondary users
2425 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2426 return;
2427 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002428 long identity = Binder.clearCallingIdentity();
2429 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002430 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2431 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002432 } finally {
2433 Binder.restoreCallingIdentity(identity);
2434 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002435 }
2436
2437 @Override
2438 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002439 checkPendingIntent(intent);
2440 checkPackageName(packageName);
2441
2442 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2443
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002444 // geo-fence manager uses the public location API, need to clear identity
2445 long identity = Binder.clearCallingIdentity();
2446 try {
2447 mGeofenceManager.removeFence(geofence, intent);
2448 } finally {
2449 Binder.restoreCallingIdentity(identity);
2450 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002451 }
2452
2453
2454 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002455 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002456 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002457 return false;
2458 }
2459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002460 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08002461 mGnssStatusProvider.registerGnssStatusCallback(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002462 } catch (RemoteException e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08002463 Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002464 return false;
2465 }
2466 return true;
2467 }
2468
Nick Pellye0fd6932012-07-11 10:26:13 -07002469 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002470 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002471 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002472 try {
Lifu Tang30f95a72016-01-07 23:20:38 -08002473 mGnssStatusProvider.unregisterGnssStatusCallback(callback);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002474 } catch (Exception e) {
Lifu Tang30f95a72016-01-07 23:20:38 -08002475 Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04002476 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002477 }
2478 }
2479
Nick Pellye0fd6932012-07-11 10:26:13 -07002480 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002481 public boolean addGnssMeasurementsListener(
gomo48f1a642017-11-10 20:35:46 -08002482 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002483 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002484 return false;
2485 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002486
2487 synchronized (mLock) {
2488 Identity callerIdentity
2489 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Wyatt Riley11cc7492018-01-17 08:48:27 -08002490 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002491 long identity = Binder.clearCallingIdentity();
2492 try {
2493 if (isThrottlingExemptLocked(callerIdentity)
2494 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002495 mActivityManager.getPackageImportance(packageName))) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002496 return mGnssMeasurementsProvider.addListener(listener);
2497 }
2498 } finally {
2499 Binder.restoreCallingIdentity(identity);
2500 }
2501
2502 return true;
2503 }
destradaaea8a8a62014-06-23 18:19:03 -07002504 }
2505
2506 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002507 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
2508 if (mGnssMeasurementsProvider != null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002509 synchronized (mLock) {
Wyatt Riley11cc7492018-01-17 08:48:27 -08002510 mGnssMeasurementsListeners.remove(listener.asBinder());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002511 mGnssMeasurementsProvider.removeListener(listener);
2512 }
Wei Liu5241a4c2015-05-11 14:00:36 -07002513 }
destradaaea8a8a62014-06-23 18:19:03 -07002514 }
2515
2516 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002517 public boolean addGnssNavigationMessageListener(
2518 IGnssNavigationMessageListener listener,
destradaa4b3e3932014-07-21 18:01:47 -07002519 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002520 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002521 return false;
2522 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002523
2524 synchronized (mLock) {
2525 Identity callerIdentity
gomo48f1a642017-11-10 20:35:46 -08002526 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Wyatt Riley11cc7492018-01-17 08:48:27 -08002527 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002528 long identity = Binder.clearCallingIdentity();
2529 try {
2530 if (isThrottlingExemptLocked(callerIdentity)
2531 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002532 mActivityManager.getPackageImportance(packageName))) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002533 return mGnssNavigationMessageProvider.addListener(listener);
2534 }
2535 } finally {
2536 Binder.restoreCallingIdentity(identity);
2537 }
2538
2539 return true;
2540 }
destradaa4b3e3932014-07-21 18:01:47 -07002541 }
2542
2543 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002544 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2545 if (mGnssNavigationMessageProvider != null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002546 synchronized (mLock) {
Wyatt Riley11cc7492018-01-17 08:48:27 -08002547 mGnssNavigationMessageListeners.remove(listener.asBinder());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002548 mGnssNavigationMessageProvider.removeListener(listener);
2549 }
Wei Liu5241a4c2015-05-11 14:00:36 -07002550 }
destradaa4b3e3932014-07-21 18:01:47 -07002551 }
2552
2553 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002554 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002555 if (provider == null) {
2556 // throw NullPointerException to remain compatible with previous implementation
2557 throw new NullPointerException();
2558 }
Victoria Lease37425c32012-10-16 16:08:48 -07002559 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2560 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002561
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002562 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04002563 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
Maggieaa080f92018-01-04 15:35:11 -08002564 != PERMISSION_GRANTED)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002565 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2566 }
2567
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002568 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002569 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002570 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07002571
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002572 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002573 }
2574 }
2575
Nick Pellye0fd6932012-07-11 10:26:13 -07002576 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002577 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002578 if (Binder.getCallingUid() != Process.myUid()) {
2579 throw new SecurityException(
2580 "calling sendNiResponse from outside of the system is not allowed");
2581 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002582 try {
2583 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002584 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002585 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002586 return false;
2587 }
2588 }
2589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002590 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05002591 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11002592 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002593 * accessed by the caller
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002594 */
Nick Pellye0fd6932012-07-11 10:26:13 -07002595 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002596 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07002597 if (mProvidersByName.get(provider) == null) {
David Christie2ff96af2014-01-30 16:09:37 -08002598 return null;
Laurent Tub7f9d252012-10-16 14:25:00 -07002599 }
2600
Victoria Lease37425c32012-10-16 16:08:48 -07002601 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2602 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002603
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002604 LocationProviderInterface p;
2605 synchronized (mLock) {
2606 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002607 }
2608
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002609 if (p == null) return null;
2610 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002611 }
2612
Jason Monkb71218a2015-06-17 14:44:39 -04002613 /**
2614 * @return null if the provider does not exist
2615 * @throws SecurityException if the provider is not allowed to be
gomo48f1a642017-11-10 20:35:46 -08002616 * accessed by the caller
Jason Monkb71218a2015-06-17 14:44:39 -04002617 */
2618 @Override
2619 public String getNetworkProviderPackage() {
2620 LocationProviderInterface p;
2621 synchronized (mLock) {
2622 if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
2623 return null;
2624 }
2625 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2626 }
2627
2628 if (p instanceof LocationProviderProxy) {
2629 return ((LocationProviderProxy) p).getConnectedPackageName();
2630 }
2631 return null;
2632 }
2633
Maggieaa080f92018-01-04 15:35:11 -08002634 /**
Maggie2a9409e2018-03-21 11:47:28 -07002635 * Returns the current location enabled/disabled status for a user
2636 *
2637 * @param userId the id of the user
2638 * @return true if location is enabled
2639 */
2640 @Override
2641 public boolean isLocationEnabledForUser(int userId) {
2642 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2643 checkInteractAcrossUsersPermission(userId);
2644
2645 long identity = Binder.clearCallingIdentity();
2646 try {
2647 synchronized (mLock) {
2648 final String allowedProviders = Settings.Secure.getStringForUser(
2649 mContext.getContentResolver(),
2650 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2651 userId);
2652 if (allowedProviders == null) {
2653 return false;
2654 }
2655 final List<String> providerList = Arrays.asList(allowedProviders.split(","));
2656 for(String provider : mRealProviders.keySet()) {
2657 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2658 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2659 continue;
2660 }
2661 if (providerList.contains(provider)) {
2662 return true;
2663 }
2664 }
2665 return false;
2666 }
2667 } finally {
2668 Binder.restoreCallingIdentity(identity);
2669 }
2670 }
2671
2672 /**
2673 * Enable or disable location for a user
2674 *
2675 * @param enabled true to enable location, false to disable location
2676 * @param userId the id of the user
2677 */
2678 @Override
2679 public void setLocationEnabledForUser(boolean enabled, int userId) {
2680 mContext.enforceCallingPermission(
2681 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2682 "Requires WRITE_SECURE_SETTINGS permission");
2683
2684 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2685 checkInteractAcrossUsersPermission(userId);
2686
2687 long identity = Binder.clearCallingIdentity();
2688 try {
2689 synchronized (mLock) {
2690 final Set<String> allRealProviders = mRealProviders.keySet();
2691 // Update all providers on device plus gps and network provider when disabling
2692 // location
2693 Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
2694 allProvidersSet.addAll(allRealProviders);
2695 // When disabling location, disable gps and network provider that could have been
2696 // enabled by location mode api.
2697 if (enabled == false) {
2698 allProvidersSet.add(LocationManager.GPS_PROVIDER);
2699 allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
2700 }
2701 if (allProvidersSet.isEmpty()) {
2702 return;
2703 }
2704 // to ensure thread safety, we write the provider name with a '+' or '-'
2705 // and let the SettingsProvider handle it rather than reading and modifying
2706 // the list of enabled providers.
2707 final String prefix = enabled ? "+" : "-";
2708 StringBuilder locationProvidersAllowed = new StringBuilder();
2709 for (String provider : allProvidersSet) {
2710 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2711 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2712 continue;
2713 }
2714 locationProvidersAllowed.append(prefix);
2715 locationProvidersAllowed.append(provider);
2716 locationProvidersAllowed.append(",");
2717 }
2718 // Remove the trailing comma
2719 locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
2720 Settings.Secure.putStringForUser(
2721 mContext.getContentResolver(),
2722 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2723 locationProvidersAllowed.toString(),
2724 userId);
2725 }
2726 } finally {
2727 Binder.restoreCallingIdentity(identity);
2728 }
2729 }
2730
2731 /**
2732 * Returns the current enabled/disabled status of a location provider and user
2733 *
2734 * @param provider name of the provider
2735 * @param userId the id of the user
2736 * @return true if the provider exists and is enabled
2737 */
2738 @Override
2739 public boolean isProviderEnabledForUser(String provider, int userId) {
2740 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2741 checkInteractAcrossUsersPermission(userId);
2742
2743 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2744 // so we discourage its use
2745 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2746
2747 int uid = Binder.getCallingUid();
2748 synchronized (mLock) {
2749 LocationProviderInterface p = mProvidersByName.get(provider);
2750 return p != null
2751 && isAllowedByUserSettingsLocked(provider, uid, userId);
2752 }
2753 }
2754
2755 /**
2756 * Enable or disable a single location provider.
2757 *
2758 * @param provider name of the provider
2759 * @param enabled true to enable the provider. False to disable the provider
2760 * @param userId the id of the user to set
2761 * @return true if the value was set, false on errors
2762 */
2763 @Override
2764 public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
2765 mContext.enforceCallingPermission(
2766 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2767 "Requires WRITE_SECURE_SETTINGS permission");
2768
2769 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2770 checkInteractAcrossUsersPermission(userId);
2771
2772 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2773 // so we discourage its use
2774 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
2775
2776 long identity = Binder.clearCallingIdentity();
2777 try {
2778 synchronized (mLock) {
2779 // No such provider exists
2780 if (!mProvidersByName.containsKey(provider)) return false;
2781
2782 // If it is a test provider, do not write to Settings.Secure
2783 if (mMockProviders.containsKey(provider)) {
2784 setTestProviderEnabled(provider, enabled);
2785 return true;
2786 }
2787
2788 // to ensure thread safety, we write the provider name with a '+' or '-'
2789 // and let the SettingsProvider handle it rather than reading and modifying
2790 // the list of enabled providers.
2791 String providerChange = (enabled ? "+" : "-") + provider;
2792 return Settings.Secure.putStringForUser(
2793 mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2794 providerChange, userId);
2795 }
2796 } finally {
2797 Binder.restoreCallingIdentity(identity);
2798 }
2799 }
2800
2801 /**
Maggieaa080f92018-01-04 15:35:11 -08002802 * Read location provider status from Settings.Secure
2803 *
2804 * @param provider the location provider to query
2805 * @param userId the user id to query
2806 * @return true if the provider is enabled
2807 */
2808 private boolean isLocationProviderEnabledForUser(String provider, int userId) {
2809 long identity = Binder.clearCallingIdentity();
2810 try {
2811 // Use system settings
2812 ContentResolver cr = mContext.getContentResolver();
2813 String allowedProviders = Settings.Secure.getStringForUser(
2814 cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
2815 return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
2816 } finally {
2817 Binder.restoreCallingIdentity(identity);
2818 }
2819 }
2820
2821 /**
Maggie2a9409e2018-03-21 11:47:28 -07002822 * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
2823 * current user id
2824 *
2825 * @param userId the user id to get or set value
2826 */
2827 private void checkInteractAcrossUsersPermission(int userId) {
2828 int uid = Binder.getCallingUid();
2829 if (UserHandle.getUserId(uid) != userId) {
2830 if (ActivityManager.checkComponentPermission(
2831 android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
2832 != PERMISSION_GRANTED) {
2833 throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
2834 }
2835 }
2836 }
2837
2838 /**
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002839 * Returns "true" if the UID belongs to a bound location provider.
2840 *
2841 * @param uid the uid
2842 * @return true if uid belongs to a bound location provider
2843 */
2844 private boolean isUidALocationProvider(int uid) {
2845 if (uid == Process.SYSTEM_UID) {
2846 return true;
2847 }
2848 if (mGeocodeProvider != null) {
David Christie1f141c12014-05-14 15:11:15 -07002849 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002850 }
2851 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002852 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002853 }
2854 return false;
2855 }
2856
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002857 private void checkCallerIsProvider() {
2858 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
Maggieaa080f92018-01-04 15:35:11 -08002859 == PERMISSION_GRANTED) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002860 return;
2861 }
2862
2863 // Previously we only used the INSTALL_LOCATION_PROVIDER
2864 // check. But that is system or signature
2865 // protection level which is not flexible enough for
2866 // providers installed oustide the system image. So
2867 // also allow providers with a UID matching the
2868 // currently bound package name
2869
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002870 if (isUidALocationProvider(Binder.getCallingUid())) {
2871 return;
2872 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002873
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002874 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2875 "or UID of a currently bound location provider");
2876 }
2877
David Christie1f141c12014-05-14 15:11:15 -07002878 /**
2879 * Returns true if the given package belongs to the given uid.
2880 */
2881 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002882 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002883 return false;
2884 }
David Christie1f141c12014-05-14 15:11:15 -07002885 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2886 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002887 return false;
2888 }
David Christie1f141c12014-05-14 15:11:15 -07002889 for (String name : packageNames) {
2890 if (packageName.equals(name)) {
2891 return true;
2892 }
2893 }
2894 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002895 }
2896
Nick Pellye0fd6932012-07-11 10:26:13 -07002897 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002898 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002899 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04002900
Nick Pelly2eeeec22012-07-18 13:13:37 -07002901 if (!location.isComplete()) {
2902 Log.w(TAG, "Dropping incomplete location: " + location);
2903 return;
2904 }
2905
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002906 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
2907 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05002908 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002909 mLocationHandler.sendMessageAtFrontOfQueue(m);
2910 }
2911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002912
Laurent Tu75defb62012-11-01 16:21:52 -07002913 private static boolean shouldBroadcastSafe(
2914 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 // Always broadcast the first update
2916 if (lastLoc == null) {
2917 return true;
2918 }
2919
Nick Pellyf1be6862012-05-15 10:53:42 -07002920 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002921 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002922 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2923 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002924 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002925 return false;
2926 }
2927
2928 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002929 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930 if (minDistance > 0.0) {
2931 if (loc.distanceTo(lastLoc) <= minDistance) {
2932 return false;
2933 }
2934 }
2935
Laurent Tu75defb62012-11-01 16:21:52 -07002936 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002937 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002938 return false;
2939 }
2940
2941 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002942 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002943 }
2944
Mike Lockwooda4903f22010-02-17 06:42:23 -05002945 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002946 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002947 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05002948 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
Laurent Tu60ec50a2012-10-04 17:00:10 -07002949 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05002950 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002951 if (p == null) return;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002952 updateLastLocationLocked(location, provider);
2953 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002954 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002955 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002956 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
2957 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07002958 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002959
David Christie1b9b7b12013-04-15 15:31:11 -07002960 // Update last known coarse interval location if enough time has passed.
2961 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2962 if (lastLocationCoarseInterval == null) {
2963 lastLocationCoarseInterval = new Location(location);
2964 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2965 }
2966 long timeDiffNanos = location.getElapsedRealtimeNanos()
2967 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2968 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
2969 lastLocationCoarseInterval.set(location);
2970 }
2971 // Don't ever return a coarse location that is more recent than the allowed update
2972 // interval (i.e. don't allow an app to keep registering and unregistering for
2973 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002974 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07002975 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2976
Laurent Tu60ec50a2012-10-04 17:00:10 -07002977 // Skip if there are no UpdateRecords for this provider.
2978 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2979 if (records == null || records.size() == 0) return;
2980
Victoria Lease09016ab2012-09-16 12:33:15 -07002981 // Fetch coarse location
2982 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002983 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002984 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2985 }
2986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002987 // Fetch latest status update time
2988 long newStatusUpdateTime = p.getStatusUpdateTime();
2989
David Christie2ff96af2014-01-30 16:09:37 -08002990 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002991 Bundle extras = new Bundle();
2992 int status = p.getStatus(extras);
2993
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002994 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002995 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002997 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002998 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002999 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003000 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003001
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003002 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
3003 if (!isCurrentProfile(receiverUserId)
3004 && !isUidALocationProvider(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003005 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003006 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003007 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003008 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003009 }
3010 continue;
3011 }
3012
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003013 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003014 if (D) {
3015 Log.d(TAG, "skipping loc update for blacklisted app: " +
3016 receiver.mIdentity.mPackageName);
3017 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003018 continue;
3019 }
3020
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003021 if (!reportLocationAccessNoThrow(
3022 receiver.mIdentity.mPid,
3023 receiver.mIdentity.mUid,
3024 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003025 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003026 if (D) {
3027 Log.d(TAG, "skipping loc update for no op app: " +
3028 receiver.mIdentity.mPackageName);
3029 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003030 continue;
3031 }
3032
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003033 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003034 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3035 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003036 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07003037 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003038 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003039 if (notifyLocation != null) {
3040 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07003041 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003042 if (lastLoc == null) {
3043 lastLoc = new Location(notifyLocation);
3044 r.mLastFixBroadcast = lastLoc;
3045 } else {
3046 lastLoc.set(notifyLocation);
3047 }
3048 if (!receiver.callLocationChangedLocked(notifyLocation)) {
3049 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
3050 receiverDead = true;
3051 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003052 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003053 }
3054 }
3055
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003056 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003057 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07003058 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003059
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003060 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003061 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003062 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08003063 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07003064 }
3065 }
3066
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003067 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003068 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003069 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003070 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003071 }
3072 deadUpdateRecords.add(r);
3073 }
3074 // track dead receivers
3075 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003076 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003077 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003078 }
3079 if (!deadReceivers.contains(receiver)) {
3080 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003081 }
3082 }
3083 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003084
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003085 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003086 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003087 for (Receiver receiver : deadReceivers) {
3088 removeUpdatesLocked(receiver);
3089 }
3090 }
3091 if (deadUpdateRecords != null) {
3092 for (UpdateRecord r : deadUpdateRecords) {
3093 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003094 }
Victoria Lease8b38b292012-12-04 15:04:43 -08003095 applyRequirementsLocked(provider);
3096 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097 }
3098
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003099 /**
3100 * Updates last location with the given location
3101 *
3102 * @param location new location to update
3103 * @param provider Location provider to update for
3104 */
3105 private void updateLastLocationLocked(Location location, String provider) {
3106 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3107 Location lastNoGPSLocation;
3108 Location lastLocation = mLastLocation.get(provider);
3109 if (lastLocation == null) {
3110 lastLocation = new Location(provider);
3111 mLastLocation.put(provider, lastLocation);
3112 } else {
3113 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3114 if (noGPSLocation == null && lastNoGPSLocation != null) {
3115 // New location has no no-GPS location: adopt last no-GPS location. This is set
3116 // directly into location because we do not want to notify COARSE clients.
3117 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3118 }
3119 }
3120 lastLocation.set(location);
3121 }
3122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003123 private class LocationWorkerHandler extends Handler {
Victoria Lease5cd731a2012-12-19 15:04:21 -08003124 public LocationWorkerHandler(Looper looper) {
3125 super(looper, null, true);
3126 }
3127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003128 @Override
3129 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003130 switch (msg.what) {
3131 case MSG_LOCATION_CHANGED:
3132 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
3133 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003134 }
3135 }
3136 }
3137
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003138 private boolean isMockProvider(String provider) {
3139 synchronized (mLock) {
3140 return mMockProviders.containsKey(provider);
3141 }
3142 }
3143
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003144 private void handleLocationChanged(Location location, boolean passive) {
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003145 // create a working copy of the incoming Location so that the service can modify it without
3146 // disturbing the caller's copy
3147 Location myLocation = new Location(location);
3148 String provider = myLocation.getProvider();
3149
3150 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
3151 // bit if location did not come from a mock provider because passive/fused providers can
3152 // forward locations from mock providers, and should not grant them legitimacy in doing so.
3153 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
3154 myLocation.setIsFromMockProvider(true);
3155 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08003156
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003157 synchronized (mLock) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08003158 if (isAllowedByCurrentUserSettingsLocked(provider)) {
3159 if (!passive) {
3160 // notify passive provider of the new location
3161 mPassiveProvider.updateLocation(myLocation);
3162 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003163 handleLocationChangedLocked(myLocation, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003164 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003165 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167
Mike Lockwoode97ae402010-09-29 15:23:46 -04003168 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
3169 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003170 public void onPackageDisappeared(String packageName, int reason) {
3171 // remove all receivers associated with this package name
3172 synchronized (mLock) {
3173 ArrayList<Receiver> deadReceivers = null;
3174
3175 for (Receiver receiver : mReceivers.values()) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003176 if (receiver.mIdentity.mPackageName.equals(packageName)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003177 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003178 deadReceivers = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003179 }
3180 deadReceivers.add(receiver);
3181 }
3182 }
3183
3184 // perform removal outside of mReceivers loop
3185 if (deadReceivers != null) {
3186 for (Receiver receiver : deadReceivers) {
3187 removeUpdatesLocked(receiver);
3188 }
3189 }
3190 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003191 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04003192 };
3193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194 // Geocoder
3195
Nick Pellye0fd6932012-07-11 10:26:13 -07003196 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003197 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003198 return mGeocodeProvider != null;
3199 }
3200
Nick Pellye0fd6932012-07-11 10:26:13 -07003201 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003202 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003203 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003204 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003205 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3206 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003207 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003208 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003209 }
3210
Mike Lockwooda55c3212009-04-15 11:10:11 -04003211
Nick Pellye0fd6932012-07-11 10:26:13 -07003212 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003213 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003214 double lowerLeftLatitude, double lowerLeftLongitude,
3215 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003216 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003217
3218 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003219 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3220 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3221 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003222 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003223 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 }
3225
3226 // Mock Providers
3227
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003228 private boolean canCallerAccessMockLocation(String opPackageName) {
3229 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3230 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003231 }
3232
Nick Pellye0fd6932012-07-11 10:26:13 -07003233 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003234 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
3235 if (!canCallerAccessMockLocation(opPackageName)) {
3236 return;
3237 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238
Mike Lockwooda4903f22010-02-17 06:42:23 -05003239 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
3240 throw new IllegalArgumentException("Cannot mock the passive location provider");
3241 }
3242
Mike Lockwood86328a92009-10-23 08:38:25 -04003243 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003244 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003245 // remove the real provider if we are replacing GPS or network provider
3246 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07003247 || LocationManager.NETWORK_PROVIDER.equals(name)
3248 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05003249 LocationProviderInterface p = mProvidersByName.get(name);
3250 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003251 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003252 }
3253 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003254 addTestProviderLocked(name, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003255 updateProvidersLocked();
3256 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003257 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003258 }
3259
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003260 private void addTestProviderLocked(String name, ProviderProperties properties) {
3261 if (mProvidersByName.get(name) != null) {
3262 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
3263 }
3264 MockProvider provider = new MockProvider(name, this, properties);
3265 addProviderLocked(provider);
3266 mMockProviders.put(name, provider);
3267 mLastLocation.put(name, null);
3268 mLastLocationCoarseInterval.put(name, null);
3269 }
3270
Nick Pellye0fd6932012-07-11 10:26:13 -07003271 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003272 public void removeTestProvider(String provider, String opPackageName) {
3273 if (!canCallerAccessMockLocation(opPackageName)) {
3274 return;
3275 }
3276
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003277 synchronized (mLock) {
Tom O'Neill07ee5d12014-03-03 17:48:35 -08003278
3279 // These methods can't be called after removing the test provider, so first make sure
Tom O'Neillfe6d3c52014-03-04 08:26:17 -08003280 // we don't leave anything dangling.
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003281 clearTestProviderEnabled(provider, opPackageName);
3282 clearTestProviderLocation(provider, opPackageName);
3283 clearTestProviderStatus(provider, opPackageName);
Tom O'Neill07ee5d12014-03-03 17:48:35 -08003284
You Kima6d0b6f2012-10-28 03:58:44 +09003285 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003286 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003287 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3288 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003289 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003290 removeProviderLocked(mProvidersByName.get(provider));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003291
3292 // reinstate real provider if available
3293 LocationProviderInterface realProvider = mRealProviders.get(provider);
3294 if (realProvider != null) {
3295 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003296 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003297 mLastLocation.put(provider, null);
David Christie1b9b7b12013-04-15 15:31:11 -07003298 mLastLocationCoarseInterval.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003299 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04003300 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 }
3302 }
3303
Nick Pellye0fd6932012-07-11 10:26:13 -07003304 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003305 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
3306 if (!canCallerAccessMockLocation(opPackageName)) {
3307 return;
3308 }
3309
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003310 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003311 MockProvider mockProvider = mMockProviders.get(provider);
3312 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003313 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3314 }
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003315
3316 // Ensure that the location is marked as being mock. There's some logic to do this in
3317 // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
3318 Location mock = new Location(loc);
3319 mock.setIsFromMockProvider(true);
3320
3321 if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
3322 // The location has an explicit provider that is different from the mock provider
3323 // name. The caller may be trying to fool us via bug 33091107.
3324 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3325 provider + "!=" + loc.getProvider());
3326 }
3327
Mike Lockwood95427cd2009-05-07 13:27:54 -04003328 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
3329 long identity = Binder.clearCallingIdentity();
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003330 mockProvider.setLocation(mock);
Mike Lockwood95427cd2009-05-07 13:27:54 -04003331 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003332 }
3333 }
3334
Nick Pellye0fd6932012-07-11 10:26:13 -07003335 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003336 public void clearTestProviderLocation(String provider, String opPackageName) {
3337 if (!canCallerAccessMockLocation(opPackageName)) {
3338 return;
3339 }
3340
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003341 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003342 MockProvider mockProvider = mMockProviders.get(provider);
3343 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003344 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3345 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003346 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 }
3348 }
3349
Nick Pellye0fd6932012-07-11 10:26:13 -07003350 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003351 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
3352 if (!canCallerAccessMockLocation(opPackageName)) {
3353 return;
3354 }
Maggie2a9409e2018-03-21 11:47:28 -07003355 setTestProviderEnabled(provider, enabled);
3356 }
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003357
Maggie2a9409e2018-03-21 11:47:28 -07003358 /** Enable or disable a test location provider. */
3359 private void setTestProviderEnabled(String provider, boolean enabled) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003360 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003361 MockProvider mockProvider = mMockProviders.get(provider);
3362 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003363 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3364 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003365 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003366 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003367 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368 mEnabledProviders.add(provider);
3369 mDisabledProviders.remove(provider);
3370 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003371 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003372 mEnabledProviders.remove(provider);
3373 mDisabledProviders.add(provider);
3374 }
3375 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04003376 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 }
3378 }
3379
Nick Pellye0fd6932012-07-11 10:26:13 -07003380 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003381 public void clearTestProviderEnabled(String provider, String opPackageName) {
3382 if (!canCallerAccessMockLocation(opPackageName)) {
3383 return;
3384 }
3385
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003386 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003387 MockProvider mockProvider = mMockProviders.get(provider);
3388 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003389 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3390 }
Mike Lockwood86328a92009-10-23 08:38:25 -04003391 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003392 mEnabledProviders.remove(provider);
3393 mDisabledProviders.remove(provider);
3394 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04003395 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 }
3397 }
3398
Nick Pellye0fd6932012-07-11 10:26:13 -07003399 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003400 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
3401 String opPackageName) {
3402 if (!canCallerAccessMockLocation(opPackageName)) {
3403 return;
3404 }
3405
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003406 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003407 MockProvider mockProvider = mMockProviders.get(provider);
3408 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003409 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3410 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003411 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003412 }
3413 }
3414
Nick Pellye0fd6932012-07-11 10:26:13 -07003415 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003416 public void clearTestProviderStatus(String provider, String opPackageName) {
3417 if (!canCallerAccessMockLocation(opPackageName)) {
3418 return;
3419 }
3420
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003421 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003422 MockProvider mockProvider = mMockProviders.get(provider);
3423 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003424 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3425 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003426 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003427 }
3428 }
3429
3430 private void log(String log) {
3431 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003432 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 }
3434 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003435
3436 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003437 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003438 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003439
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04003440 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003441 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3442 if (mGnssMetricsProvider != null) {
3443 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3444 }
3445 return;
3446 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003447 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003449 for (Receiver receiver : mReceivers.values()) {
3450 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003451 }
David Christie2ff96af2014-01-30 16:09:37 -08003452 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003453 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3454 pw.println(" " + entry.getKey() + ":");
3455 for (UpdateRecord record : entry.getValue()) {
3456 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003457 }
3458 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003459 pw.println(" Active GnssMeasurement Listeners:");
3460 for (Identity identity : mGnssMeasurementsListeners.values()) {
3461 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3462 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3463 }
3464 pw.println(" Active GnssNavigationMessage Listeners:");
3465 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3466 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3467 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3468 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003469 pw.println(" Overlay Provider Packages:");
3470 for (LocationProviderInterface provider : mProviders) {
3471 if (provider instanceof LocationProviderProxy) {
3472 pw.println(" " + provider.getName() + ": "
3473 + ((LocationProviderProxy) provider).getConnectedPackageName());
3474 }
3475 }
David Christie2ff96af2014-01-30 16:09:37 -08003476 pw.println(" Historical Records by Provider:");
3477 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3478 : mRequestStatistics.statistics.entrySet()) {
3479 PackageProviderKey key = entry.getKey();
3480 PackageStatistics stats = entry.getValue();
3481 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003483 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003484 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3485 String provider = entry.getKey();
3486 Location location = entry.getValue();
3487 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003489
David Christie1b9b7b12013-04-15 15:31:11 -07003490 pw.println(" Last Known Locations Coarse Intervals:");
3491 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3492 String provider = entry.getKey();
3493 Location location = entry.getValue();
3494 pw.println(" " + provider + ": " + location);
3495 }
3496
Nick Pellye0fd6932012-07-11 10:26:13 -07003497 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003499 if (mEnabledProviders.size() > 0) {
3500 pw.println(" Enabled Providers:");
3501 for (String i : mEnabledProviders) {
3502 pw.println(" " + i);
3503 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003505 }
3506 if (mDisabledProviders.size() > 0) {
3507 pw.println(" Disabled Providers:");
3508 for (String i : mDisabledProviders) {
3509 pw.println(" " + i);
3510 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003511 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003512 pw.append(" ");
3513 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 if (mMockProviders.size() > 0) {
3515 pw.println(" Mock Providers:");
3516 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003517 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003518 }
3519 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003520
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003521 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3522 pw.println(" Throttling Whitelisted Packages:");
3523 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3524 pw.println(" " + packageName);
3525 }
3526 }
3527
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003528 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003529 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003530
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003531 if (args.length > 0 && "short".equals(args[0])) {
3532 return;
3533 }
gomo48f1a642017-11-10 20:35:46 -08003534 for (LocationProviderInterface provider : mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003535 pw.print(provider.getName() + " Internal State");
3536 if (provider instanceof LocationProviderProxy) {
3537 LocationProviderProxy proxy = (LocationProviderProxy) provider;
3538 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003539 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003540 pw.println(":");
3541 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003542 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003543 if (mGnssBatchingInProgress) {
3544 pw.println(" GNSS batching in progress");
3545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003546 }
3547 }
3548}