blob: 2346cfc07a8394331ebd6a5253404d350408ed87 [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;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070020import static android.location.LocationProvider.AVAILABLE;
Soonil Nagarkar94749f72018-11-08 11:46:43 -080021import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS;
Maggieaa080f92018-01-04 15:35:11 -080022
Soonil Nagarkar1575a042018-10-24 17:54:54 -070023import static com.android.internal.util.Preconditions.checkState;
24
Wei Wang980b7c22018-12-06 17:53:00 -080025import android.Manifest;
Wyatt Rileycf879db2017-01-12 13:57:38 -080026import android.annotation.NonNull;
Wyatt Riley49097c02018-03-15 09:14:43 -070027import android.annotation.Nullable;
Maggieaa080f92018-01-04 15:35:11 -080028import android.app.ActivityManager;
29import android.app.AppOpsManager;
30import android.app.PendingIntent;
31import android.content.BroadcastReceiver;
32import android.content.ContentResolver;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.pm.ApplicationInfo;
37import android.content.pm.PackageInfo;
38import android.content.pm.PackageManager;
39import android.content.pm.PackageManager.NameNotFoundException;
40import android.content.pm.PackageManagerInternal;
41import android.content.pm.ResolveInfo;
42import android.content.pm.Signature;
43import android.content.res.Resources;
44import android.database.ContentObserver;
45import android.hardware.location.ActivityRecognitionHardware;
46import android.location.Address;
47import android.location.Criteria;
48import android.location.GeocoderParams;
49import android.location.Geofence;
gomo226b7b72018-12-12 16:49:39 -080050import android.location.GnssMeasurementCorrections;
Maggieaa080f92018-01-04 15:35:11 -080051import android.location.IBatchedLocationCallback;
52import android.location.IGnssMeasurementsListener;
53import android.location.IGnssNavigationMessageListener;
54import android.location.IGnssStatusListener;
Maggieaa080f92018-01-04 15:35:11 -080055import android.location.IGpsGeofenceHardware;
56import android.location.ILocationListener;
57import android.location.ILocationManager;
58import android.location.INetInitiatedListener;
59import android.location.Location;
60import android.location.LocationManager;
Maggieaa080f92018-01-04 15:35:11 -080061import android.location.LocationRequest;
62import android.os.Binder;
63import android.os.Bundle;
64import android.os.Handler;
65import android.os.IBinder;
66import android.os.Looper;
Soonil Nagarkar68257742019-01-09 19:42:34 +000067import android.os.Message;
Maggieaa080f92018-01-04 15:35:11 -080068import android.os.PowerManager;
69import android.os.Process;
70import android.os.RemoteException;
71import android.os.SystemClock;
72import android.os.UserHandle;
73import android.os.UserManager;
74import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000075import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080076import android.provider.Settings;
77import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080078import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080079import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080080import android.util.EventLog;
81import android.util.Log;
82import android.util.Slog;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -070083
destradaaea8a8a62014-06-23 18:19:03 -070084import com.android.internal.content.PackageMonitor;
85import com.android.internal.location.ProviderProperties;
86import com.android.internal.location.ProviderRequest;
87import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070088import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060089import com.android.internal.util.DumpUtils;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070090import com.android.server.location.AbstractLocationProvider;
destradaaa4fa3b52014-07-09 10:46:39 -070091import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070092import com.android.server.location.GeocoderProxy;
93import com.android.server.location.GeofenceManager;
94import com.android.server.location.GeofenceProxy;
Yu-Han Yang3557cc72018-03-21 12:48:36 -070095import com.android.server.location.GnssBatchingProvider;
Lifu Tang818aa2c2016-02-01 01:52:00 -080096import com.android.server.location.GnssLocationProvider;
97import com.android.server.location.GnssMeasurementsProvider;
98import com.android.server.location.GnssNavigationMessageProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -080099import com.android.server.location.GnssStatusListenerHelper;
destradaaea8a8a62014-06-23 18:19:03 -0700100import com.android.server.location.LocationBlacklist;
101import com.android.server.location.LocationFudger;
destradaaea8a8a62014-06-23 18:19:03 -0700102import com.android.server.location.LocationProviderProxy;
103import com.android.server.location.LocationRequestStatistics;
104import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
105import com.android.server.location.LocationRequestStatistics.PackageStatistics;
106import com.android.server.location.MockProvider;
107import com.android.server.location.PassiveProvider;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -0700108
Mike Lockwood43e33f22010-03-26 10:41:48 -0400109import java.io.FileDescriptor;
110import java.io.PrintWriter;
111import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700112import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400113import java.util.HashMap;
114import java.util.HashSet;
115import java.util.List;
116import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800117import java.util.Map.Entry;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800118import java.util.NoSuchElementException;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400119import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120
121/**
122 * The service class that manages LocationProviders and issues location
123 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800125public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800127 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700128
Olivier Gaillard7a222662017-11-20 16:07:24 +0000129 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130
Victoria Lease37425c32012-10-16 16:08:48 -0700131 // Location resolution level: no location data whatsoever
132 private static final int RESOLUTION_LEVEL_NONE = 0;
133 // Location resolution level: coarse location data only
134 private static final int RESOLUTION_LEVEL_COARSE = 1;
135 // Location resolution level: fine location data
136 private static final int RESOLUTION_LEVEL_FINE = 2;
137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700139 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400140 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700141 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
142
143 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700144 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700145 private static final String FUSED_LOCATION_SERVICE_ACTION =
146 "com.android.location.service.FusedLocationProvider";
147
148 private static final int MSG_LOCATION_CHANGED = 1;
149
David Christie1b9b7b12013-04-15 15:31:11 -0700150 private static final long NANOS_PER_MILLI = 1000000L;
151
David Christie0b837452013-07-29 16:02:13 -0700152 // The maximum interval a location request can have and still be considered "high power".
153 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
154
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700155 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800156 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700157
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800158 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800159 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800160
Wei Wangdd070f22018-06-21 11:29:40 -0700161 // Default value for maximum age of last location returned to applications with foreground-only
162 // location permissions.
163 private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
164
Nick Pellyf1be6862012-05-15 10:53:42 -0700165 // Location Providers may sometimes deliver location updates
166 // slightly faster that requested - provide grace period so
167 // we don't unnecessarily filter events that are otherwise on
168 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700170
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700171 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
172
173 private final Context mContext;
Soonil Nagarkar68257742019-01-09 19:42:34 +0000174 private final AppOpsManager mAppOps;
175
176 // used internally for synchronization
177 private final Object mLock = new Object();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700178
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700179 // --- fields below are final after systemRunning() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700180 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700182 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700183 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800184 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700185 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700186 private GeocoderProxy mGeocodeProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800187 private GnssStatusListenerHelper mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700188 private INetInitiatedListener mNetInitiatedListener;
Soonil Nagarkar68257742019-01-09 19:42:34 +0000189 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700190 private PassiveProvider mPassiveProvider; // track passive provider for special cases
191 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800192 private GnssMeasurementsProvider mGnssMeasurementsProvider;
193 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Wei Wang980b7c22018-12-06 17:53:00 -0800194 private String mLocationControllerExtraPackage;
195 private boolean mLocationControllerExtraPackageEnabled;
Wei Liu5241a4c2015-05-11 14:00:36 -0700196 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700197
Soonil Nagarkar68257742019-01-09 19:42:34 +0000198 // --- fields below are protected by mLock ---
199
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700200 // Mock (test) providers
201 private final HashMap<String, MockProvider> mMockProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800202 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700204 // all receivers
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800205 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700207 // currently installed providers (with mocks replacing real providers)
Soonil Nagarkar68257742019-01-09 19:42:34 +0000208 private final ArrayList<LocationProvider> mProviders =
209 new ArrayList<>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400210
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700211 // real providers, saved here when mocked out
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700212 private final HashMap<String, LocationProvider> mRealProviders =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800213 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700215 // mapping from provider name to provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700216 private final HashMap<String, LocationProvider> mProvidersByName =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800217 new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700219 // mapping from provider name to all its UpdateRecords
220 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800221 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700222
David Christie2ff96af2014-01-30 16:09:37 -0800223 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
224
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700225 // mapping from provider name to last known location
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800226 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
David Christie1b9b7b12013-04-15 15:31:11 -0700228 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
229 // locations stored here are not fudged for coarse permissions.
230 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800231 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700232
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800233 // all providers that operate over proxy, for authorizing incoming location and whitelisting
234 // throttling
Soonil Nagarkar68257742019-01-09 19:42:34 +0000235 private final ArrayList<LocationProviderProxy> mProxyProviders =
236 new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800238 private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800239
Wyatt Riley11cc7492018-01-17 08:48:27 -0800240 private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800241
Wyatt Riley11cc7492018-01-17 08:48:27 -0800242 private final ArrayMap<IBinder, Identity>
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800243 mGnssNavigationMessageListeners = new ArrayMap<>();
244
Victoria Lease38389b62012-09-30 11:44:22 -0700245 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700246 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800247 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700248
Soonil Nagarkar68257742019-01-09 19:42:34 +0000249 // Maximum age of last location returned to clients with foreground-only location permissions.
250 private long mLastLocationMaxAgeMs;
251
Lifu Tang9363b942016-02-16 18:07:00 -0800252 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800253
Siddharth Raybb608c82017-03-16 11:33:34 -0700254 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700255
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700256 private GnssBatchingProvider mGnssBatchingProvider;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800257 private IBatchedLocationCallback mGnssBatchingCallback;
258 private LinkedCallback mGnssBatchingDeathCallback;
259 private boolean mGnssBatchingInProgress = false;
260
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700261 public LocationManagerService(Context context) {
262 super();
263 mContext = context;
Soonil Nagarkar68257742019-01-09 19:42:34 +0000264 mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800265
Svet Ganovadc1cf42015-06-15 16:36:24 -0700266 // Let the package manager query which are the default location
267 // providers as they get certain permissions granted by default.
268 PackageManagerInternal packageManagerInternal = LocalServices.getService(
269 PackageManagerInternal.class);
270 packageManagerInternal.setLocationPackagesProvider(
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700271 userId -> mContext.getResources().getStringArray(
272 com.android.internal.R.array.config_locationProviderPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700273
Soonil Nagarkar68257742019-01-09 19:42:34 +0000274 if (D) Log.d(TAG, "Constructed");
275
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700276 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700277 }
278
Svetoslav Ganova0027152013-06-25 14:59:53 -0700279 public void systemRunning() {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000280 synchronized (mLock) {
281 if (D) Log.d(TAG, "systemRunning()");
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700282
Soonil Nagarkar68257742019-01-09 19:42:34 +0000283 // fetch package manager
284 mPackageManager = mContext.getPackageManager();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800285
Soonil Nagarkar68257742019-01-09 19:42:34 +0000286 // fetch power manager
287 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800288
Soonil Nagarkar68257742019-01-09 19:42:34 +0000289 // fetch activity manager
290 mActivityManager
291 = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800292
Soonil Nagarkar68257742019-01-09 19:42:34 +0000293 // prepare worker thread
294 mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800295
Soonil Nagarkar68257742019-01-09 19:42:34 +0000296 // prepare mLocationHandler's dependents
297 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
298 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
299 mBlacklist.init();
300 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800301
Soonil Nagarkar68257742019-01-09 19:42:34 +0000302 // Monitor for app ops mode changes.
303 AppOpsManager.OnOpChangedListener callback
304 = new AppOpsManager.OnOpChangedInternalListener() {
305 public void onOpChanged(int op, String packageName) {
306 mLocationHandler.post(() -> {
307 synchronized (mLock) {
308 for (Receiver receiver : mReceivers.values()) {
309 receiver.updateMonitoring(true);
310 }
311 applyAllProviderRequirementsLocked();
312 }
313 });
314 }
315 };
316 mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
317 AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800318
Soonil Nagarkar68257742019-01-09 19:42:34 +0000319 PackageManager.OnPermissionsChangedListener permissionListener = uid -> {
320 synchronized (mLock) {
321 applyAllProviderRequirementsLocked();
322 }
323 };
324 mPackageManager.addOnPermissionsChangeListener(permissionListener);
David Christieb870dbf2015-06-22 12:42:53 -0700325
Soonil Nagarkar68257742019-01-09 19:42:34 +0000326 // listen for background/foreground changes
327 ActivityManager.OnUidImportanceListener uidImportanceListener =
328 (uid, importance) -> mLocationHandler.post(
329 () -> onUidImportanceChanged(uid, importance));
330 mActivityManager.addOnUidImportanceListener(uidImportanceListener,
331 FOREGROUND_IMPORTANCE_CUTOFF);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800332
Soonil Nagarkar68257742019-01-09 19:42:34 +0000333 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
334 updateUserProfiles(mCurrentUserId);
335
336 updateBackgroundThrottlingWhitelistLocked();
337 updateLastLocationMaxAgeLocked();
338
339 // prepare providers
340 loadProvidersLocked();
341 updateProvidersSettingsLocked();
342 for (LocationProvider provider : mProviders) {
343 applyRequirementsLocked(provider.getName());
344 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800345 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700346
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700347 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700348 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700349 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Soonil Nagarkar68257742019-01-09 19:42:34 +0000350 new ContentObserver(mLocationHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800351 @Override
352 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000353 synchronized (mLock) {
354 updateProvidersSettingsLocked();
355 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800356 }
357 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800358 mContext.getContentResolver().registerContentObserver(
359 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
360 true,
Soonil Nagarkar68257742019-01-09 19:42:34 +0000361 new ContentObserver(mLocationHandler) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800362 @Override
363 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000364 synchronized (mLock) {
365 for (LocationProvider provider : mProviders) {
366 applyRequirementsLocked(provider.getName());
367 }
368 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800369 }
370 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800371 mContext.getContentResolver().registerContentObserver(
Soonil Nagarkar68257742019-01-09 19:42:34 +0000372 Settings.Global.getUriFor(Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS),
373 true,
374 new ContentObserver(mLocationHandler) {
375 @Override
376 public void onChange(boolean selfChange) {
377 synchronized (mLock) {
378 updateLastLocationMaxAgeLocked();
379 }
380 }
381 }
382 );
383 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800384 Settings.Global.getUriFor(
385 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
386 true,
Soonil Nagarkar68257742019-01-09 19:42:34 +0000387 new ContentObserver(mLocationHandler) {
gomo48f1a642017-11-10 20:35:46 -0800388 @Override
389 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000390 synchronized (mLock) {
391 updateBackgroundThrottlingWhitelistLocked();
392 for (LocationProvider provider : mProviders) {
393 applyRequirementsLocked(provider.getName());
394 }
395 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800396 }
gomo48f1a642017-11-10 20:35:46 -0800397 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700398
Soonil Nagarkar68257742019-01-09 19:42:34 +0000399 mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700400
Victoria Lease38389b62012-09-30 11:44:22 -0700401 // listen for user change
402 IntentFilter intentFilter = new IntentFilter();
403 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700404 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
405 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700406
407 mContext.registerReceiverAsUser(new BroadcastReceiver() {
408 @Override
409 public void onReceive(Context context, Intent intent) {
410 String action = intent.getAction();
411 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
412 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700413 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
414 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
415 updateUserProfiles(mCurrentUserId);
Victoria Lease38389b62012-09-30 11:44:22 -0700416 }
417 }
Soonil Nagarkar68257742019-01-09 19:42:34 +0000418 }, UserHandle.ALL, intentFilter, null, mLocationHandler);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700419 }
420
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700421 private void onUidImportanceChanged(int uid, int importance) {
422 boolean foreground = isImportanceForeground(importance);
423 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
Soonil Nagarkar68257742019-01-09 19:42:34 +0000424 synchronized (mLock) {
425 for (Entry<String, ArrayList<UpdateRecord>> entry
426 : mRecordsByProvider.entrySet()) {
427 String provider = entry.getKey();
428 for (UpdateRecord record : entry.getValue()) {
429 if (record.mReceiver.mIdentity.mUid == uid
430 && record.mIsForegroundUid != foreground) {
431 if (D) {
432 Log.d(TAG, "request from uid " + uid + " is now "
433 + (foreground ? "foreground" : "background)"));
434 }
435 record.updateForeground(foreground);
436
437 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
438 affectedProviders.add(provider);
439 }
440 }
441 }
442 }
443 for (String provider : affectedProviders) {
444 applyRequirementsLocked(provider);
445 }
446
447 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
448 Identity callerIdentity = entry.getValue();
449 if (callerIdentity.mUid == uid) {
gomo48f1a642017-11-10 20:35:46 -0800450 if (D) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000451 Log.d(TAG, "gnss measurements listener from uid " + uid
452 + " is now " + (foreground ? "foreground" : "background)"));
453 }
454 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
455 mGnssMeasurementsProvider.addListener(
456 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
457 callerIdentity.mUid, callerIdentity.mPackageName);
458 } else {
459 mGnssMeasurementsProvider.removeListener(
460 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
461 }
462 }
463 }
464
465 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
466 Identity callerIdentity = entry.getValue();
467 if (callerIdentity.mUid == uid) {
468 if (D) {
469 Log.d(TAG, "gnss navigation message listener from uid "
470 + uid + " is now "
gomo48f1a642017-11-10 20:35:46 -0800471 + (foreground ? "foreground" : "background)"));
472 }
Soonil Nagarkar68257742019-01-09 19:42:34 +0000473 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
474 mGnssNavigationMessageProvider.addListener(
475 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
476 callerIdentity.mUid, callerIdentity.mPackageName);
477 } else {
478 mGnssNavigationMessageProvider.removeListener(
479 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700480 }
481 }
482 }
Anil Admal75b9fd62018-11-28 11:22:50 -0800483
Soonil Nagarkar68257742019-01-09 19:42:34 +0000484 // TODO(b/120449926): The GNSS status listeners should be handled similar to the above.
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700485 }
486 }
487
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800488 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700489 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800490 }
491
Soonil Nagarkar68257742019-01-09 19:42:34 +0000492 /**
493 * Makes a list of userids that are related to the current user. This is
494 * relevant when using managed profiles. Otherwise the list only contains
495 * the current user.
496 *
497 * @param currentUserId the current user, who might have an alter-ego.
498 */
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800499 private void updateUserProfiles(int currentUserId) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000500 int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
501 synchronized (mLock) {
502 mCurrentUserProfiles = profileIds;
503 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800504 }
505
Soonil Nagarkar68257742019-01-09 19:42:34 +0000506 /**
507 * Checks if the specified userId matches any of the current foreground
508 * users stored in mCurrentUserProfiles.
509 */
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800510 private boolean isCurrentProfile(int userId) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000511 synchronized (mLock) {
512 return ArrayUtils.contains(mCurrentUserProfiles, userId);
513 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800514 }
515
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700516 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500517 PackageManager pm = mContext.getPackageManager();
518 String systemPackageName = mContext.getPackageName();
519 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
520
521 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
522 new Intent(FUSED_LOCATION_SERVICE_ACTION),
523 PackageManager.GET_META_DATA, mCurrentUserId);
524 for (ResolveInfo rInfo : rInfos) {
525 String packageName = rInfo.serviceInfo.packageName;
526
527 // Check that the signature is in the list of supported sigs. If it's not in
528 // this list the standard provider binding logic won't bind to it.
529 try {
530 PackageInfo pInfo;
531 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
532 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
533 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
534 ", but has wrong signature, ignoring");
535 continue;
536 }
537 } catch (NameNotFoundException e) {
538 Log.e(TAG, "missing package: " + packageName);
539 continue;
540 }
541
542 // Get the version info
543 if (rInfo.serviceInfo.metaData == null) {
544 Log.w(TAG, "Found fused provider without metadata: " + packageName);
545 continue;
546 }
547
548 int version = rInfo.serviceInfo.metaData.getInt(
549 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
550 if (version == 0) {
551 // This should be the fallback fused location provider.
552
553 // Make sure it's in the system partition.
554 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
555 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
556 continue;
557 }
558
559 // Check that the fallback is signed the same as the OS
560 // as a proxy for coreApp="true"
561 if (pm.checkSignatures(systemPackageName, packageName)
562 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800563 if (D) {
564 Log.d(TAG, "Fallback candidate not signed the same as system: "
565 + packageName);
566 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500567 continue;
568 }
569
570 // Found a valid fallback.
571 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
572 return;
573 } else {
574 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
575 }
576 }
577
578 throw new IllegalStateException("Unable to find a fused location provider that is in the "
579 + "system partition with version 0 and signed with the platform certificate. "
580 + "Such a package is needed to provide a default fused location provider in the "
581 + "event that no other fused location provider has been installed or is currently "
582 + "available. For example, coreOnly boot mode when decrypting the data "
583 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
584 }
585
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700586 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700587 // create a passive location provider, which is always enabled
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700588 LocationProvider passiveProviderManager = new LocationProvider(
589 LocationManager.PASSIVE_PROVIDER);
590 PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager);
591
Soonil Nagarkar68257742019-01-09 19:42:34 +0000592 addProviderLocked(passiveProviderManager);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700593 mPassiveProvider = passiveProvider;
594
Lifu Tang30f95a72016-01-07 23:20:38 -0800595 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700596 // Create a gps location provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700597 LocationProvider gnssProviderManager = new LocationProvider(
598 LocationManager.GPS_PROVIDER);
599 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
600 gnssProviderManager,
Soonil Nagarkar68257742019-01-09 19:42:34 +0000601 mLocationHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700602
Lifu Tang9363b942016-02-16 18:07:00 -0800603 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800604 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700605 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800606 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
607 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000608 addProviderLocked(gnssProviderManager);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700609 mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager);
Lifu Tang818aa2c2016-02-01 01:52:00 -0800610 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
611 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800612 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700613 }
614
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700615 /*
616 Load package name(s) containing location provider support.
617 These packages can contain services implementing location providers:
618 Geocoder Provider, Network Location Provider, and
619 Fused Location Provider. They will each be searched for
620 service components implementing these providers.
621 The location framework also has support for installation
622 of new location providers at run-time. The new package does not
623 have to be explicitly listed here, however it must have a signature
624 that matches the signature of at least one package on this list.
625 */
626 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500627 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700628 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800629 if (D) {
630 Log.d(TAG, "certificates for location providers pulled from: " +
631 Arrays.toString(pkgs));
632 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500633
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700634 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700635
636 // bind to network provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700637
638 LocationProvider networkProviderManager = new LocationProvider(
639 LocationManager.NETWORK_PROVIDER);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700640 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
641 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700642 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700643 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700644 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
645 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700646 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700647 if (networkProvider != null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700648 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700649 mProxyProviders.add(networkProvider);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000650 addProviderLocked(networkProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700651 } else {
gomo48f1a642017-11-10 20:35:46 -0800652 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700653 }
654
655 // bind to fused provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700656 LocationProvider fusedProviderManager = new LocationProvider(
657 LocationManager.FUSED_PROVIDER);
658 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700659 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700660 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700662 com.android.internal.R.bool.config_enableFusedLocationOverlay,
663 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700664 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700665 if (fusedProvider != null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000666 addProviderLocked(fusedProviderManager);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700667 mProxyProviders.add(fusedProvider);
668 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700669 } else {
670 Slog.e(TAG, "no fused location provider found",
671 new IllegalStateException("Location service needs a fused location provider"));
672 }
673
674 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700675 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
676 com.android.internal.R.bool.config_enableGeocoderOverlay,
677 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700678 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700679 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800680 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700681 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700682
destradaaf9a274c2014-07-25 15:11:56 -0700683 // bind to geofence provider
684 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800685 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700686 com.android.internal.R.string.config_geofenceProviderPackageName,
687 com.android.internal.R.array.config_locationProviderPackageNames,
Wei Liu5241a4c2015-05-11 14:00:36 -0700688 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900689 null);
destradaaf9a274c2014-07-25 15:11:56 -0700690 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800691 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700692 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900693
destradaa6e2fe752015-06-23 17:25:53 -0700694 // bind to hardware activity recognition
695 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
696 ActivityRecognitionHardware activityRecognitionHardware = null;
697 if (activityRecognitionHardwareIsSupported) {
698 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700699 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700700 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700701 }
destradaa6e2fe752015-06-23 17:25:53 -0700702 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
703 mContext,
destradaa6e2fe752015-06-23 17:25:53 -0700704 activityRecognitionHardwareIsSupported,
705 activityRecognitionHardware,
706 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
707 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
708 com.android.internal.R.array.config_locationProviderPackageNames);
709 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700710 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700711 }
destradaaa4fa3b52014-07-09 10:46:39 -0700712
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900713 String[] testProviderStrings = resources.getStringArray(
714 com.android.internal.R.array.config_testLocationProviders);
715 for (String testProviderString : testProviderStrings) {
716 String fragments[] = testProviderString.split(",");
717 String name = fragments[0].trim();
718 if (mProvidersByName.get(name) != null) {
719 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
720 }
721 ProviderProperties properties = new ProviderProperties(
722 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
723 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
724 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
725 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
726 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
727 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
728 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
729 Integer.parseInt(fragments[8]) /* powerRequirement */,
730 Integer.parseInt(fragments[9]) /* accuracy */);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000731 addTestProviderLocked(name, properties);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900732 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700733 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700734
Soonil Nagarkar68257742019-01-09 19:42:34 +0000735 /**
736 * Called when the device's active user changes.
737 *
738 * @param userId the new active user's UserId
739 */
Victoria Lease38389b62012-09-30 11:44:22 -0700740 private void switchUser(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800741 if (mCurrentUserId == userId) {
742 return;
743 }
Victoria Lease83762d22012-10-03 13:51:17 -0700744 mBlacklist.switchUser(userId);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000745 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
746 synchronized (mLock) {
747 mLastLocation.clear();
748 mLastLocationCoarseInterval.clear();
749 updateUserProfiles(userId);
750 updateProvidersSettingsLocked();
751 mCurrentUserId = userId;
752 }
Victoria Lease38389b62012-09-30 11:44:22 -0700753 }
754
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800755 private static final class Identity {
756 final int mUid;
757 final int mPid;
758 final String mPackageName;
759
760 Identity(int uid, int pid, String packageName) {
761 mUid = uid;
762 mPid = pid;
763 mPackageName = packageName;
764 }
765 }
766
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700767 private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
768
769 private final String mName;
770 private AbstractLocationProvider mProvider;
771
772 // whether the provider is enabled in location settings
773 private boolean mSettingsEnabled;
774
775 // whether the provider considers itself enabled
776 private volatile boolean mEnabled;
777
778 @Nullable
779 private volatile ProviderProperties mProperties;
780
781 private LocationProvider(String name) {
782 mName = name;
783 // TODO: initialize settings enabled?
784 }
785
786 @Override
787 public void onAttachProvider(AbstractLocationProvider provider, boolean initiallyEnabled) {
788 checkState(mProvider == null);
789
790 // the provider is not yet fully constructed at this point, so we may not do anything
791 // except save a reference for later use here. do not call any provider methods.
792 mProvider = provider;
793 mEnabled = initiallyEnabled;
794 mProperties = null;
795 }
796
797 public String getName() {
798 return mName;
799 }
800
801 public boolean isEnabled() {
802 return mSettingsEnabled && mEnabled;
803 }
804
805 @Nullable
806 public ProviderProperties getProperties() {
807 return mProperties;
808 }
809
810 public void setRequest(ProviderRequest request, WorkSource workSource) {
811 mProvider.setRequest(request, workSource);
812 }
813
814 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
815 pw.println(mName + " provider:");
816 pw.println(" setting=" + mSettingsEnabled);
817 pw.println(" enabled=" + mEnabled);
818 pw.println(" properties=" + mProperties);
819 mProvider.dump(fd, pw, args);
820 }
821
822 public long getStatusUpdateTime() {
823 return mProvider.getStatusUpdateTime();
824 }
825
826 public int getStatus(Bundle extras) {
827 return mProvider.getStatus(extras);
828 }
829
830 public void sendExtraCommand(String command, Bundle extras) {
831 mProvider.sendExtraCommand(command, extras);
832 }
833
834 // called from any thread
835 @Override
836 public void onReportLocation(Location location) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000837 runOnHandler(() -> LocationManagerService.this.reportLocation(location,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700838 mProvider == mPassiveProvider));
839 }
840
841 // called from any thread
842 @Override
843 public void onReportLocation(List<Location> locations) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000844 runOnHandler(() -> LocationManagerService.this.reportLocationBatch(locations));
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700845 }
846
847 // called from any thread
848 @Override
849 public void onSetEnabled(boolean enabled) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000850 runOnHandler(() -> {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700851 if (enabled == mEnabled) {
852 return;
853 }
854
855 mEnabled = enabled;
856
857 if (!mSettingsEnabled) {
858 // this provider was disabled in settings anyways, so a change to it's own
859 // enabled status won't have any affect.
860 return;
861 }
862
863 // traditionally clients can listen for changes to the LOCATION_PROVIDERS_ALLOWED
864 // setting to detect when providers are enabled or disabled (even though they aren't
865 // supposed to). to continue to support this we must force a change to this setting.
866 // we use the fused provider because this is forced to be always enabled in settings
867 // anyways, and so won't have any visible effect beyond triggering content observers
868 Settings.Secure.putStringForUser(mContext.getContentResolver(),
869 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
870 "+" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
871 Settings.Secure.putStringForUser(mContext.getContentResolver(),
872 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
873 "-" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
874
Soonil Nagarkar68257742019-01-09 19:42:34 +0000875 synchronized (mLock) {
876 if (!enabled) {
877 // If any provider has been disabled, clear all last locations for all
878 // providers. This is to be on the safe side in case a provider has location
879 // derived from this disabled provider.
880 mLastLocation.clear();
881 mLastLocationCoarseInterval.clear();
882 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700883
Soonil Nagarkar68257742019-01-09 19:42:34 +0000884 updateProviderListenersLocked(mName);
885 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800886
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700887 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
888 UserHandle.ALL);
889 });
890 }
891
892 @Override
893 public void onSetProperties(ProviderProperties properties) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000894 runOnHandler(() -> mProperties = properties);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700895 }
896
897 private void setSettingsEnabled(boolean enabled) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000898 synchronized (mLock) {
899 if (mSettingsEnabled == enabled) {
900 return;
901 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700902
Soonil Nagarkar68257742019-01-09 19:42:34 +0000903 mSettingsEnabled = enabled;
904 if (!mSettingsEnabled) {
905 // if any provider has been disabled, clear all last locations for all
906 // providers. this is to be on the safe side in case a provider has location
907 // derived from this disabled provider.
908 mLastLocation.clear();
909 mLastLocationCoarseInterval.clear();
910 updateProviderListenersLocked(mName);
911 } else if (mEnabled) {
912 updateProviderListenersLocked(mName);
913 }
914 }
915 }
916
917 private void runOnHandler(Runnable runnable) {
918 if (Looper.myLooper() == mLocationHandler.getLooper()) {
919 runnable.run();
920 } else {
921 mLocationHandler.post(runnable);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700922 }
923 }
924 }
925
Victoria Lease38389b62012-09-30 11:44:22 -0700926 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
928 * location updates.
929 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700930 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -0700931 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800932 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700933 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700934
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700935 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700937 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700938 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
939 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700940
gomo48f1a642017-11-10 20:35:46 -0800941 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700942
David Christie0b837452013-07-29 16:02:13 -0700943 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700944 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700945 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700946 private boolean mOpHighPowerMonitoring;
947 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700948 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700950 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -0700951 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700954 if (listener != null) {
955 mKey = listener.asBinder();
956 } else {
957 mKey = intent;
958 }
Victoria Lease37425c32012-10-16 16:08:48 -0700959 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800960 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +0000961 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -0700962 workSource = null;
963 }
964 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -0700965 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -0700966
Dianne Hackborn1304f4a2013-07-09 18:17:27 -0700967 updateMonitoring(true);
968
Victoria Lease0aa28602013-05-29 15:28:26 -0700969 // construct/configure wakelock
970 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -0700971 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800972 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -0700973 }
974 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -0700975
976 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
977 // only need to release it once.
978 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 }
980
981 @Override
982 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800983 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 }
985
986 @Override
987 public int hashCode() {
988 return mKey.hashCode();
989 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400990
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 @Override
992 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700993 StringBuilder s = new StringBuilder();
994 s.append("Reciever[");
995 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700997 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700999 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001001 for (String p : mUpdateRecords.keySet()) {
1002 s.append(" ").append(mUpdateRecords.get(p).toString());
1003 }
Wei Wangdd070f22018-06-21 11:29:40 -07001004 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001005 s.append("]");
1006 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
1008
David Christie15b31912013-08-13 15:54:32 -07001009 /**
1010 * Update AppOp monitoring for this receiver.
1011 *
1012 * @param allow If true receiver is currently active, if false it's been removed.
1013 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001014 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001015 if (mHideFromAppOps) {
1016 return;
1017 }
1018
David Christie15b31912013-08-13 15:54:32 -07001019 boolean requestingLocation = false;
1020 boolean requestingHighPowerLocation = false;
1021 if (allow) {
1022 // See if receiver has any enabled update records. Also note if any update records
1023 // are high power (has a high power provider with an interval under a threshold).
1024 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001025 if (isAllowedByUserSettingsLockedForUser(updateRecord.mProvider,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001026 mCurrentUserId)) {
David Christie15b31912013-08-13 15:54:32 -07001027 requestingLocation = true;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001028 LocationManagerService.LocationProvider locationProvider
David Christie2ff96af2014-01-30 16:09:37 -08001029 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -07001030 ProviderProperties properties = locationProvider != null
1031 ? locationProvider.getProperties() : null;
1032 if (properties != null
1033 && properties.mPowerRequirement == Criteria.POWER_HIGH
1034 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1035 requestingHighPowerLocation = true;
1036 break;
1037 }
1038 }
1039 }
1040 }
1041
David Christie0b837452013-07-29 16:02:13 -07001042 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001043 mOpMonitoring = updateMonitoring(
1044 requestingLocation,
1045 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001046 AppOpsManager.OP_MONITOR_LOCATION);
1047
1048 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001049 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001050 mOpHighPowerMonitoring = updateMonitoring(
1051 requestingHighPowerLocation,
1052 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001053 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001054 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001055 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001056 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1057 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1058 }
David Christie0b837452013-07-29 16:02:13 -07001059 }
1060
1061 /**
1062 * Update AppOps monitoring for a single location request and op type.
1063 *
gomo48f1a642017-11-10 20:35:46 -08001064 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001065 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001066 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001067 * @return True if monitoring is on for this request/op after updating.
1068 */
1069 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1070 int op) {
1071 if (!currentlyMonitoring) {
1072 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001073 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001074 == AppOpsManager.MODE_ALLOWED;
1075 }
1076 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001077 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001078 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001079 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001080 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001081 return false;
1082 }
1083 }
1084
1085 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001086 }
1087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 public boolean isListener() {
1089 return mListener != null;
1090 }
1091
1092 public boolean isPendingIntent() {
1093 return mPendingIntent != null;
1094 }
1095
1096 public ILocationListener getListener() {
1097 if (mListener != null) {
1098 return mListener;
1099 }
1100 throw new IllegalStateException("Request for non-existent listener");
1101 }
1102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1104 if (mListener != null) {
1105 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001106 synchronized (this) {
1107 // synchronize to ensure incrementPendingBroadcastsLocked()
1108 // is called before decrementPendingBroadcasts()
1109 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001110 // call this after broadcasting so we do not increment
1111 // if we throw an exeption.
1112 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 } catch (RemoteException e) {
1115 return false;
1116 }
1117 } else {
1118 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001119 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1121 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001122 synchronized (this) {
1123 // synchronize to ensure incrementPendingBroadcastsLocked()
1124 // is called before decrementPendingBroadcasts()
Soonil Nagarkar68257742019-01-09 19:42:34 +00001125 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001126 getResolutionPermission(mAllowedResolutionLevel),
1127 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001128 // call this after broadcasting so we do not increment
1129 // if we throw an exeption.
1130 incrementPendingBroadcastsLocked();
1131 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 } catch (PendingIntent.CanceledException e) {
1133 return false;
1134 }
1135 }
1136 return true;
1137 }
1138
1139 public boolean callLocationChangedLocked(Location location) {
1140 if (mListener != null) {
1141 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001142 synchronized (this) {
1143 // synchronize to ensure incrementPendingBroadcastsLocked()
1144 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001145 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001146 // call this after broadcasting so we do not increment
1147 // if we throw an exeption.
1148 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 } catch (RemoteException e) {
1151 return false;
1152 }
1153 } else {
1154 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001155 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1156 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001158 synchronized (this) {
1159 // synchronize to ensure incrementPendingBroadcastsLocked()
1160 // is called before decrementPendingBroadcasts()
Soonil Nagarkar68257742019-01-09 19:42:34 +00001161 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001162 getResolutionPermission(mAllowedResolutionLevel),
1163 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001164 // call this after broadcasting so we do not increment
1165 // if we throw an exeption.
1166 incrementPendingBroadcastsLocked();
1167 }
1168 } catch (PendingIntent.CanceledException e) {
1169 return false;
1170 }
1171 }
1172 return true;
1173 }
1174
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001175 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001176 // First update AppOp monitoring.
1177 // An app may get/lose location access as providers are enabled/disabled.
1178 updateMonitoring(true);
1179
Mike Lockwood48f17512009-04-23 09:12:08 -07001180 if (mListener != null) {
1181 try {
1182 synchronized (this) {
1183 // synchronize to ensure incrementPendingBroadcastsLocked()
1184 // is called before decrementPendingBroadcasts()
1185 if (enabled) {
1186 mListener.onProviderEnabled(provider);
1187 } else {
1188 mListener.onProviderDisabled(provider);
1189 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001190 // call this after broadcasting so we do not increment
1191 // if we throw an exeption.
1192 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001193 }
1194 } catch (RemoteException e) {
1195 return false;
1196 }
1197 } else {
1198 Intent providerIntent = new Intent();
1199 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1200 try {
1201 synchronized (this) {
1202 // synchronize to ensure incrementPendingBroadcastsLocked()
1203 // is called before decrementPendingBroadcasts()
Soonil Nagarkar68257742019-01-09 19:42:34 +00001204 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001205 getResolutionPermission(mAllowedResolutionLevel),
1206 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001207 // call this after broadcasting so we do not increment
1208 // if we throw an exeption.
1209 incrementPendingBroadcastsLocked();
1210 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 } catch (PendingIntent.CanceledException e) {
1212 return false;
1213 }
1214 }
1215 return true;
1216 }
1217
Nick Pellyf1be6862012-05-15 10:53:42 -07001218 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001220 if (D) Log.d(TAG, "Location listener died");
1221
Soonil Nagarkar68257742019-01-09 19:42:34 +00001222 synchronized (mLock) {
1223 removeUpdatesLocked(this);
1224 }
1225 synchronized (this) {
1226 clearPendingBroadcastsLocked();
1227 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001228 }
1229
Nick Pellye0fd6932012-07-11 10:26:13 -07001230 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001231 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1232 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001233 synchronized (this) {
1234 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001235 }
1236 }
1237
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001238 // this must be called while synchronized by caller in a synchronized block
1239 // containing the sending of the broadcaset
1240 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001241 mPendingBroadcasts++;
1242 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001243 }
1244
1245 private void decrementPendingBroadcastsLocked() {
1246 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001247 if (mWakeLock.isHeld()) {
1248 mWakeLock.release();
1249 }
1250 }
1251 }
1252
1253 public void clearPendingBroadcastsLocked() {
1254 if (mPendingBroadcasts > 0) {
1255 mPendingBroadcasts = 0;
1256 if (mWakeLock.isHeld()) {
1257 mWakeLock.release();
1258 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001259 }
1260 }
1261 }
1262
Nick Pellye0fd6932012-07-11 10:26:13 -07001263 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001264 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001265 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001266 //the receiver list if it is not found. If it is not found then the
1267 //LocationListener was removed when it had a pending broadcast and should
1268 //not be added back.
Soonil Nagarkar68257742019-01-09 19:42:34 +00001269 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001270 IBinder binder = listener.asBinder();
1271 Receiver receiver = mReceivers.get(binder);
1272 if (receiver != null) {
1273 synchronized (receiver) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001274 // so wakelock calls will succeed
1275 long identity = Binder.clearCallingIdentity();
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001276 receiver.decrementPendingBroadcastsLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +00001277 Binder.restoreCallingIdentity(identity);
David Christie2ff96af2014-01-30 16:09:37 -08001278 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001279 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 }
1282
Soonil Nagarkar68257742019-01-09 19:42:34 +00001283 /**
1284 * Returns the year of the GNSS hardware.
1285 */
Lifu Tang82f893d2016-01-21 18:15:33 -08001286 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001287 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001288 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001289 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001290 } else {
1291 return 0;
1292 }
1293 }
1294
Soonil Nagarkar68257742019-01-09 19:42:34 +00001295
1296 /**
1297 * Returns the model name of the GNSS hardware.
1298 */
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001299 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001300 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001301 public String getGnssHardwareModelName() {
1302 if (mGnssSystemInfoProvider != null) {
1303 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1304 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001305 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001306 }
1307 }
1308
Soonil Nagarkar68257742019-01-09 19:42:34 +00001309 /**
1310 * Runs some checks for GNSS (FINE) level permissions, used by several methods which directly
1311 * (try to) access GNSS information at this layer.
1312 */
Wyatt Rileycf879db2017-01-12 13:57:38 -08001313 private boolean hasGnssPermissions(String packageName) {
1314 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1315 checkResolutionLevelIsSufficientForProviderUse(
1316 allowedResolutionLevel,
1317 LocationManager.GPS_PROVIDER);
1318
1319 int pid = Binder.getCallingPid();
1320 int uid = Binder.getCallingUid();
1321 long identity = Binder.clearCallingIdentity();
1322 boolean hasLocationAccess;
1323 try {
1324 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1325 } finally {
1326 Binder.restoreCallingIdentity(identity);
1327 }
1328
1329 return hasLocationAccess;
1330 }
1331
Soonil Nagarkar68257742019-01-09 19:42:34 +00001332 /**
1333 * Returns the GNSS batching size, if available.
1334 */
Wyatt Rileycf879db2017-01-12 13:57:38 -08001335 @Override
1336 public int getGnssBatchSize(String packageName) {
1337 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1338 "Location Hardware permission not granted to access hardware batching");
1339
1340 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001341 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001342 } else {
1343 return 0;
1344 }
1345 }
1346
Soonil Nagarkar68257742019-01-09 19:42:34 +00001347 /**
1348 * Adds a callback for GNSS Batching events, if permissions allow, which are transported
1349 * to potentially multiple listeners by the BatchedLocationCallbackTransport above this.
1350 */
Wyatt Rileycf879db2017-01-12 13:57:38 -08001351 @Override
1352 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1353 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1354 "Location Hardware permission not granted to access hardware batching");
1355
1356 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1357 return false;
1358 }
1359
1360 mGnssBatchingCallback = callback;
1361 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1362 try {
1363 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1364 } catch (RemoteException e) {
1365 // if the remote process registering the listener is already dead, just swallow the
1366 // exception and return
1367 Log.e(TAG, "Remote listener already died.", e);
1368 return false;
1369 }
1370
1371 return true;
1372 }
1373
1374 private class LinkedCallback implements IBinder.DeathRecipient {
1375 private final IBatchedLocationCallback mCallback;
1376
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001377 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001378 mCallback = callback;
1379 }
1380
1381 @NonNull
1382 public IBatchedLocationCallback getUnderlyingListener() {
1383 return mCallback;
1384 }
1385
1386 @Override
1387 public void binderDied() {
1388 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1389 stopGnssBatch();
1390 removeGnssBatchingCallback();
1391 }
1392 }
1393
Soonil Nagarkar68257742019-01-09 19:42:34 +00001394 /**
1395 * Removes callback for GNSS batching
1396 */
Wyatt Rileycf879db2017-01-12 13:57:38 -08001397 @Override
1398 public void removeGnssBatchingCallback() {
1399 try {
1400 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1401 0 /* flags */);
1402 } catch (NoSuchElementException e) {
1403 // if the death callback isn't connected (it should be...), log error, swallow the
1404 // exception and return
1405 Log.e(TAG, "Couldn't unlink death callback.", e);
1406 }
1407 mGnssBatchingCallback = null;
1408 mGnssBatchingDeathCallback = null;
1409 }
1410
Soonil Nagarkar68257742019-01-09 19:42:34 +00001411
1412 /**
1413 * Starts GNSS batching, if available.
1414 */
Wyatt Rileycf879db2017-01-12 13:57:38 -08001415 @Override
1416 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1417 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1418 "Location Hardware permission not granted to access hardware batching");
1419
1420 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1421 return false;
1422 }
1423
1424 if (mGnssBatchingInProgress) {
1425 // Current design does not expect multiple starts to be called repeatedly
1426 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1427 // Try to clean up anyway, and continue
1428 stopGnssBatch();
1429 }
1430
1431 mGnssBatchingInProgress = true;
1432 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1433 }
1434
Soonil Nagarkar68257742019-01-09 19:42:34 +00001435 /**
1436 * Flushes a GNSS batch in progress
1437 */
Wyatt Rileycf879db2017-01-12 13:57:38 -08001438 @Override
1439 public void flushGnssBatch(String packageName) {
1440 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1441 "Location Hardware permission not granted to access hardware batching");
1442
1443 if (!hasGnssPermissions(packageName)) {
1444 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1445 return;
1446 }
1447
1448 if (!mGnssBatchingInProgress) {
1449 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1450 }
1451
1452 if (mGnssBatchingProvider != null) {
gomo48f1a642017-11-10 20:35:46 -08001453 mGnssBatchingProvider.flush();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001454 }
1455 }
1456
Soonil Nagarkar68257742019-01-09 19:42:34 +00001457 /**
1458 * Stops GNSS batching
1459 */
Wyatt Rileycf879db2017-01-12 13:57:38 -08001460 @Override
1461 public boolean stopGnssBatch() {
1462 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1463 "Location Hardware permission not granted to access hardware batching");
1464
1465 if (mGnssBatchingProvider != null) {
1466 mGnssBatchingInProgress = false;
1467 return mGnssBatchingProvider.stop();
gomo48f1a642017-11-10 20:35:46 -08001468 } else {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001469 return false;
1470 }
1471 }
1472
1473 @Override
1474 public void reportLocationBatch(List<Location> locations) {
1475 checkCallerIsProvider();
1476
1477 // Currently used only for GNSS locations - update permissions check if changed
Soonil Nagarkar68257742019-01-09 19:42:34 +00001478 if (isAllowedByUserSettingsLockedForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001479 if (mGnssBatchingCallback == null) {
1480 Slog.e(TAG, "reportLocationBatch() called without active Callback");
1481 return;
1482 }
1483 try {
1484 mGnssBatchingCallback.onLocationBatch(locations);
1485 } catch (RemoteException e) {
1486 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1487 }
1488 } else {
1489 Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
1490 }
1491 }
1492
Soonil Nagarkar68257742019-01-09 19:42:34 +00001493 private void addProviderLocked(LocationProvider provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001494 mProviders.add(provider);
1495 mProvidersByName.put(provider.getName(), provider);
1496 }
1497
Soonil Nagarkar68257742019-01-09 19:42:34 +00001498 private void removeProviderLocked(LocationProvider provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001499 mProviders.remove(provider);
1500 mProvidersByName.remove(provider.getName());
1501 }
1502
Soonil Nagarkar68257742019-01-09 19:42:34 +00001503 /**
1504 * Returns "true" if access to the specified location provider is allowed by the specified
1505 * user's settings. Access to all location providers is forbidden to non-location-provider
1506 * processes belonging to background users.
1507 *
1508 * @param provider the name of the location provider
1509 * @param userId the user id to query
1510 */
1511 private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001512 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001513 return isLocationEnabledForUser(userId);
Maggie2a9409e2018-03-21 11:47:28 -07001514 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001515 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001516 return isLocationEnabledForUser(userId);
Maggie2a9409e2018-03-21 11:47:28 -07001517 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001518 synchronized (mLock) {
1519 if (mMockProviders.containsKey(provider)) {
1520 return isLocationEnabledForUser(userId);
1521 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001522 }
1523
1524 long identity = Binder.clearCallingIdentity();
1525 try {
1526 // Use system settings
1527 ContentResolver cr = mContext.getContentResolver();
1528 String allowedProviders = Settings.Secure.getStringForUser(
1529 cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
1530 return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
1531 } finally {
1532 Binder.restoreCallingIdentity(identity);
1533 }
Maggie2a9409e2018-03-21 11:47:28 -07001534 }
1535
Soonil Nagarkar68257742019-01-09 19:42:34 +00001536
1537 /**
1538 * Returns "true" if access to the specified location provider is allowed by the specified
1539 * user's settings. Access to all location providers is forbidden to non-location-provider
1540 * processes belonging to background users.
1541 *
1542 * @param provider the name of the location provider
1543 * @param uid the requestor's UID
1544 * @param userId the user id to query
1545 */
1546 private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
Amith Yamasanib27528d2014-06-05 15:02:10 -07001547 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001548 return false;
1549 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001550 return isAllowedByUserSettingsLockedForUser(provider, userId);
Victoria Lease09eeaec2013-02-05 11:34:13 -08001551 }
1552
Soonil Nagarkar68257742019-01-09 19:42:34 +00001553 /**
1554 * Returns the permission string associated with the specified resolution level.
1555 *
1556 * @param resolutionLevel the resolution level
1557 * @return the permission string
1558 */
Victoria Lease37425c32012-10-16 16:08:48 -07001559 private String getResolutionPermission(int resolutionLevel) {
1560 switch (resolutionLevel) {
1561 case RESOLUTION_LEVEL_FINE:
1562 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1563 case RESOLUTION_LEVEL_COARSE:
1564 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1565 default:
1566 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001568 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001569
Soonil Nagarkar68257742019-01-09 19:42:34 +00001570 /**
1571 * Returns the resolution level allowed to the given PID/UID pair.
1572 *
1573 * @param pid the PID
1574 * @param uid the UID
1575 * @return resolution level allowed to the pid/uid pair
1576 */
Victoria Lease37425c32012-10-16 16:08:48 -07001577 private int getAllowedResolutionLevel(int pid, int uid) {
1578 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001579 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001580 return RESOLUTION_LEVEL_FINE;
1581 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001582 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001583 return RESOLUTION_LEVEL_COARSE;
1584 } else {
1585 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001586 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001587 }
1588
Soonil Nagarkar68257742019-01-09 19:42:34 +00001589 /**
1590 * Returns the resolution level allowed to the caller
1591 *
1592 * @return resolution level allowed to caller
1593 */
Victoria Lease37425c32012-10-16 16:08:48 -07001594 private int getCallerAllowedResolutionLevel() {
1595 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1596 }
1597
Soonil Nagarkar68257742019-01-09 19:42:34 +00001598 /**
1599 * Throw SecurityException if specified resolution level is insufficient to use geofences.
1600 *
1601 * @param allowedResolutionLevel resolution level allowed to caller
1602 */
Victoria Lease37425c32012-10-16 16:08:48 -07001603 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1604 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001605 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
1608
Soonil Nagarkar68257742019-01-09 19:42:34 +00001609 /**
1610 * Return the minimum resolution level required to use the specified location provider.
1611 *
1612 * @param provider the name of the location provider
1613 * @return minimum resolution level required for provider
1614 */
Victoria Lease37425c32012-10-16 16:08:48 -07001615 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001616 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1617 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1618 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001619 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001620 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1621 LocationManager.FUSED_PROVIDER.equals(provider)) {
1622 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001623 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001624 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001625 for (LocationProvider lp : mProviders) {
1626 if (!lp.getName().equals(provider)) {
1627 continue;
1628 }
1629
Laurent Tu941221c2012-10-04 14:21:52 -07001630 ProviderProperties properties = lp.getProperties();
1631 if (properties != null) {
1632 if (properties.mRequiresSatellite) {
1633 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001634 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001635 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1636 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001637 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001638 }
1639 }
1640 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001641 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001642
Victoria Lease37425c32012-10-16 16:08:48 -07001643 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001644 }
1645
Soonil Nagarkar68257742019-01-09 19:42:34 +00001646 /**
1647 * Throw SecurityException if specified resolution level is insufficient to use the named
1648 * location provider.
1649 *
1650 * @param allowedResolutionLevel resolution level allowed to caller
1651 * @param providerName the name of the location provider
1652 */
Victoria Lease37425c32012-10-16 16:08:48 -07001653 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1654 String providerName) {
1655 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1656 if (allowedResolutionLevel < requiredResolutionLevel) {
1657 switch (requiredResolutionLevel) {
1658 case RESOLUTION_LEVEL_FINE:
1659 throw new SecurityException("\"" + providerName + "\" location provider " +
1660 "requires ACCESS_FINE_LOCATION permission.");
1661 case RESOLUTION_LEVEL_COARSE:
1662 throw new SecurityException("\"" + providerName + "\" location provider " +
1663 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1664 default:
1665 throw new SecurityException("Insufficient permission for \"" + providerName +
1666 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001667 }
1668 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001669 }
1670
Soonil Nagarkar68257742019-01-09 19:42:34 +00001671 /**
1672 * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
1673 * for battery).
1674 */
1675 private void checkDeviceStatsAllowed() {
1676 mContext.enforceCallingOrSelfPermission(
1677 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
1678 }
1679
1680 private void checkUpdateAppOpsAllowed() {
1681 mContext.enforceCallingOrSelfPermission(
1682 android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
1683 }
1684
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001685 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001686 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1687 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001688 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001689 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001690 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001691 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001692 }
1693 return -1;
1694 }
1695
Wei Wangb86334f2018-07-03 16:33:24 -07001696 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001697 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001698 case RESOLUTION_LEVEL_COARSE:
1699 return AppOpsManager.OPSTR_COARSE_LOCATION;
1700 case RESOLUTION_LEVEL_FINE:
1701 return AppOpsManager.OPSTR_FINE_LOCATION;
1702 case RESOLUTION_LEVEL_NONE:
1703 // The client is not allowed to get any location, so both FINE and COARSE ops will
1704 // be denied. Pick the most restrictive one to be safe.
1705 return AppOpsManager.OPSTR_FINE_LOCATION;
1706 default:
1707 // Use the most restrictive ops if not sure.
1708 return AppOpsManager.OPSTR_FINE_LOCATION;
1709 }
1710 }
1711
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001712 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001713 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001714 int op = resolutionLevelToOp(allowedResolutionLevel);
1715 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001716 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1717 return false;
1718 }
1719 }
David Christieb870dbf2015-06-22 12:42:53 -07001720
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001721 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001722 }
1723
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001724 private boolean checkLocationAccess(int pid, int uid, String packageName,
1725 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001726 int op = resolutionLevelToOp(allowedResolutionLevel);
1727 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001728 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001729 return false;
1730 }
1731 }
David Christieb870dbf2015-06-22 12:42:53 -07001732
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001733 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001734 }
1735
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001736 /**
Maggie91e630c2018-01-24 17:31:46 -08001737 * Returns all providers by name, including passive and the ones that are not permitted to
1738 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001739 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001740 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 public List<String> getAllProviders() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001742 ArrayList<String> out;
1743 synchronized (mLock) {
1744 out = new ArrayList<>(mProviders.size());
1745 for (LocationProvider provider : mProviders) {
1746 String name = provider.getName();
1747 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1748 continue;
1749 }
1750 out.add(name);
Maggie91e630c2018-01-24 17:31:46 -08001751 }
1752 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001753 if (D) Log.d(TAG, "getAllProviders()=" + out);
1754 return out;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 }
1756
Mike Lockwood03ca2162010-04-01 08:10:09 -07001757 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001758 * Return all providers by name, that match criteria and are optionally
1759 * enabled.
1760 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001761 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001762 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001763 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001764 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Soonil Nagarkar68257742019-01-09 19:42:34 +00001765 ArrayList<String> out;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001766 int uid = Binder.getCallingUid();
Soonil Nagarkar68257742019-01-09 19:42:34 +00001767 long identity = Binder.clearCallingIdentity();
1768 try {
1769 synchronized (mLock) {
1770 out = new ArrayList<>(mProviders.size());
1771 for (LocationProvider provider : mProviders) {
1772 String name = provider.getName();
1773 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1774 continue;
1775 }
1776 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
1777 if (enabledOnly
1778 && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
1779 continue;
1780 }
1781 if (criteria != null
1782 && !android.location.LocationProvider.propertiesMeetCriteria(
1783 name, provider.getProperties(), criteria)) {
1784 continue;
1785 }
1786 out.add(name);
1787 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001788 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001789 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001790 } finally {
1791 Binder.restoreCallingIdentity(identity);
1792 }
1793
1794 if (D) Log.d(TAG, "getProviders()=" + out);
1795 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001796 }
1797
1798 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001799 * Return the name of the best provider given a Criteria object.
1800 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001801 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001802 * has been deprecated as well. So this method now uses
1803 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001804 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001805 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001806 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
1807 String result;
1808
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001809 List<String> providers = getProviders(criteria, enabledOnly);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001810 if (!providers.isEmpty()) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001811 result = pickBest(providers);
1812 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1813 return result;
1814 }
1815 providers = getProviders(null, enabledOnly);
1816 if (!providers.isEmpty()) {
1817 result = pickBest(providers);
1818 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
1819 return result;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001820 }
1821
Soonil Nagarkar68257742019-01-09 19:42:34 +00001822 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + null);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001823 return null;
1824 }
1825
Soonil Nagarkar68257742019-01-09 19:42:34 +00001826 private String pickBest(List<String> providers) {
1827 if (providers.contains(LocationManager.GPS_PROVIDER)) {
1828 return LocationManager.GPS_PROVIDER;
1829 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1830 return LocationManager.NETWORK_PROVIDER;
1831 } else {
1832 return providers.get(0);
1833 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001834 }
1835
Soonil Nagarkar68257742019-01-09 19:42:34 +00001836 @Override
1837 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
1838 LocationProvider p = mProvidersByName.get(provider);
1839 if (p == null) {
1840 throw new IllegalArgumentException("provider=" + provider);
1841 }
1842
1843 boolean result = android.location.LocationProvider.propertiesMeetCriteria(
1844 p.getName(), p.getProperties(), criteria);
1845 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
1846 return result;
1847 }
1848
1849 private void updateProvidersSettingsLocked() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001850 for (LocationProvider p : mProviders) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001851 p.setSettingsEnabled(isAllowedByUserSettingsLockedForUser(p.getName(), mCurrentUserId));
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001852 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001853
1854 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1855 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 }
1857
Soonil Nagarkar68257742019-01-09 19:42:34 +00001858 private void updateProviderListenersLocked(String provider) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001859 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001860 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001862 boolean enabled = p.isEnabled();
1863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1867 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001868 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001869 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001870 // Sends a notification message to the receiver
1871 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1872 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001873 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001874 }
1875 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 }
1879 }
1880
1881 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001882 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001883 removeUpdatesLocked(deadReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 }
1885 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001886
Soonil Nagarkar68257742019-01-09 19:42:34 +00001887 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 }
1889
Soonil Nagarkar68257742019-01-09 19:42:34 +00001890 private void applyRequirementsLocked(String provider) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001891 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001892 if (p == null) return;
1893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001895 WorkSource worksource = new WorkSource();
1896 ProviderRequest providerRequest = new ProviderRequest();
1897
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001898 ContentResolver resolver = mContext.getContentResolver();
1899 long backgroundThrottleInterval = Settings.Global.getLong(
1900 resolver,
1901 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1902 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
1903
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001904 if (p.isEnabled() && records != null && !records.isEmpty()) {
1905 // initialize the low power mode to true and set to false if any of the records requires
1906 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001907 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001908 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001909 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001910 record.mReceiver.mIdentity.mPid,
1911 record.mReceiver.mIdentity.mUid,
1912 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001913 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001914 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001915 long interval = locationRequest.getInterval();
1916
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001917 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001918 if (!record.mIsForegroundUid) {
1919 interval = Math.max(interval, backgroundThrottleInterval);
1920 }
1921 if (interval != locationRequest.getInterval()) {
1922 locationRequest = new LocationRequest(locationRequest);
1923 locationRequest.setInterval(interval);
1924 }
1925 }
1926
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001927 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001928 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08001929 if (!locationRequest.isLowPowerMode()) {
1930 providerRequest.lowPowerMode = false;
1931 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001932 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001933 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001934 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001935 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001936 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001937 }
1938 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001939
1940 if (providerRequest.reportLocation) {
1941 // calculate who to blame for power
1942 // This is somewhat arbitrary. We pick a threshold interval
1943 // that is slightly higher that the minimum interval, and
1944 // spread the blame across all applications with a request
1945 // under that threshold.
1946 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1947 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001948 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001949 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001950
1951 // Don't assign battery blame for update records whose
1952 // client has no permission to receive location data.
1953 if (!providerRequest.locationRequests.contains(locationRequest)) {
1954 continue;
1955 }
1956
Victoria Leaseb711d572012-10-02 13:14:11 -07001957 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001958 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00001959 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07001960 worksource.add(record.mReceiver.mWorkSource);
1961 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00001962 // Assign blame to caller if there's no WorkSource associated with
1963 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07001964 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001965 record.mReceiver.mIdentity.mUid,
1966 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001967 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001968 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001969 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001970 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 }
1972 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001973
1974 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1975 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 }
1977
Narayan Kamath32684dd2018-01-08 17:32:51 +00001978 /**
1979 * Whether a given {@code WorkSource} associated with a Location request is valid.
1980 */
1981 private static boolean isValidWorkSource(WorkSource workSource) {
1982 if (workSource.size() > 0) {
1983 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
1984 // by tags.
1985 return workSource.getName(0) != null;
1986 } else {
1987 // For now, make sure callers have supplied an attribution tag for use with
1988 // AppOpsManager. This might be relaxed in the future.
1989 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
1990 return workChains != null && !workChains.isEmpty() &&
1991 workChains.get(0).getAttributionTag() != null;
1992 }
1993 }
1994
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001995 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001996 public String[] getBackgroundThrottlingWhitelist() {
1997 synchronized (mLock) {
1998 return mBackgroundThrottlePackageWhitelist.toArray(
1999 new String[0]);
2000 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002001 }
2002
Soonil Nagarkar68257742019-01-09 19:42:34 +00002003 private void updateBackgroundThrottlingWhitelistLocked() {
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002004 String setting = Settings.Global.getString(
gomo48f1a642017-11-10 20:35:46 -08002005 mContext.getContentResolver(),
2006 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002007 if (setting == null) {
2008 setting = "";
2009 }
2010
2011 mBackgroundThrottlePackageWhitelist.clear();
2012 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08002013 SystemConfig.getInstance().getAllowUnthrottledLocation());
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002014 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08002015 Arrays.asList(setting.split(",")));
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08002016 }
2017
Soonil Nagarkar68257742019-01-09 19:42:34 +00002018 private void updateLastLocationMaxAgeLocked() {
2019 mLastLocationMaxAgeMs =
2020 Settings.Global.getLong(
2021 mContext.getContentResolver(),
2022 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2023 DEFAULT_LAST_LOCATION_MAX_AGE_MS);
2024 }
2025
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002026 private boolean isThrottlingExemptLocked(Identity identity) {
2027 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002028 return true;
2029 }
2030
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002031 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002032 return true;
2033 }
2034
2035 for (LocationProviderProxy provider : mProxyProviders) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002036 if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002037 return true;
2038 }
2039 }
2040
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002041 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002042 }
2043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 private class UpdateRecord {
2045 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002046 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002047 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002048 private final Receiver mReceiver;
2049 private boolean mIsForegroundUid;
2050 private Location mLastFixBroadcast;
2051 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052
2053 /**
2054 * Note: must be constructed with lock held.
2055 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002056 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002057 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002058 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002059 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002061 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002062 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002063
2064 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2065 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002066 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 mRecordsByProvider.put(provider, records);
2068 }
2069 if (!records.contains(this)) {
2070 records.add(this);
2071 }
David Christie2ff96af2014-01-30 16:09:37 -08002072
2073 // Update statistics for historical location requests by package/provider
2074 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002075 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2076 mIsForegroundUid);
2077 }
2078
2079 /**
2080 * Method to be called when record changes foreground/background
2081 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002082 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002083 mIsForegroundUid = isForeground;
2084 mRequestStatistics.updateForeground(
2085 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002086 }
2087
2088 /**
David Christie2ff96af2014-01-30 16:09:37 -08002089 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002090 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002091 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002092 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002093
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002094 // remove from mRecordsByProvider
2095 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2096 if (globalRecords != null) {
2097 globalRecords.remove(this);
2098 }
2099
2100 if (!removeReceiver) return; // the caller will handle the rest
2101
2102 // remove from Receiver#mUpdateRecords
2103 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002104 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002105
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002106 // and also remove the Receiver if it has no more update records
2107 if (receiverRecords.size() == 0) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002108 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002109 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 }
2111
2112 @Override
2113 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002114 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002115 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2116 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002117 + ")" + " " + mRealRequest + " "
2118 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 }
2121
Soonil Nagarkar68257742019-01-09 19:42:34 +00002122 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002123 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002124 IBinder binder = listener.asBinder();
2125 Receiver receiver = mReceivers.get(binder);
2126 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002127 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2128 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002129 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002130 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002131 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002132 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002133 return null;
2134 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002135 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002136 }
2137 return receiver;
2138 }
2139
Soonil Nagarkar68257742019-01-09 19:42:34 +00002140 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002141 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002142 Receiver receiver = mReceivers.get(intent);
2143 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002144 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2145 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002146 mReceivers.put(intent, receiver);
2147 }
2148 return receiver;
2149 }
2150
Victoria Lease37425c32012-10-16 16:08:48 -07002151 /**
2152 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2153 * and consistency requirements.
2154 *
2155 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002156 * @return a version of request that meets the given resolution and consistency requirements
2157 * @hide
2158 */
gomo48f1a642017-11-10 20:35:46 -08002159 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2160 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002161 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002162 if (!callerHasLocationHardwarePermission) {
2163 // allow setting low power mode only for callers with location hardware permission
2164 sanitizedRequest.setLowPowerMode(false);
2165 }
Victoria Lease37425c32012-10-16 16:08:48 -07002166 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2167 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002168 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002169 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002170 break;
2171 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002172 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002173 break;
2174 }
2175 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002176 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2177 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002178 }
Victoria Lease37425c32012-10-16 16:08:48 -07002179 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2180 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002181 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002182 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002183 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002184 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002185 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002186 }
Victoria Lease37425c32012-10-16 16:08:48 -07002187 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002188 }
2189
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002190 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002191 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002192 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002193 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002194 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002195 String[] packages = mPackageManager.getPackagesForUid(uid);
2196 if (packages == null) {
2197 throw new SecurityException("invalid UID " + uid);
2198 }
2199 for (String pkg : packages) {
2200 if (packageName.equals(pkg)) return;
2201 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002202 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002203 }
2204
Soonil Nagarkar68257742019-01-09 19:42:34 +00002205 private void checkPendingIntent(PendingIntent intent) {
2206 if (intent == null) {
2207 throw new IllegalArgumentException("invalid pending intent: " + null);
2208 }
2209 }
2210
2211 private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
2212 int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
2213 if (intent == null && listener == null) {
2214 throw new IllegalArgumentException("need either listener or intent");
2215 } else if (intent != null && listener != null) {
2216 throw new IllegalArgumentException("cannot register both listener and intent");
2217 } else if (intent != null) {
2218 checkPendingIntent(intent);
2219 return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
2220 } else {
2221 return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
2222 }
2223 }
2224
Nick Pellye0fd6932012-07-11 10:26:13 -07002225 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002226 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002227 PendingIntent intent, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002228 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2229 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002230 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2231 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2232 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07002233 WorkSource workSource = request.getWorkSource();
Narayan Kamath32684dd2018-01-08 17:32:51 +00002234 if (workSource != null && !workSource.isEmpty()) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002235 checkDeviceStatsAllowed();
David Christie40e57822013-07-30 11:36:48 -07002236 }
2237 boolean hideFromAppOps = request.getHideFromAppOps();
2238 if (hideFromAppOps) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002239 checkUpdateAppOpsAllowed();
David Christie82edc9b2013-07-19 11:31:42 -07002240 }
gomo48f1a642017-11-10 20:35:46 -08002241 boolean callerHasLocationHardwarePermission =
2242 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002243 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002244 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2245 callerHasLocationHardwarePermission);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002246
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002247 final int pid = Binder.getCallingPid();
2248 final int uid = Binder.getCallingUid();
Soonil Nagarkar68257742019-01-09 19:42:34 +00002249 // providers may use public location API's, need to clear identity
2250 long identity = Binder.clearCallingIdentity();
2251 try {
2252 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2253 // a location.
2254 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002255
Soonil Nagarkar68257742019-01-09 19:42:34 +00002256 synchronized (mLock) {
2257 Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
2258 packageName, workSource, hideFromAppOps);
2259 requestLocationUpdatesLocked(sanitizedRequest, recevier, uid, packageName);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002260 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002261 } finally {
2262 Binder.restoreCallingIdentity(identity);
2263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002264 }
2265
Soonil Nagarkar68257742019-01-09 19:42:34 +00002266 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002267 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002268 // Figure out the provider. Either its explicitly request (legacy use cases), or
2269 // use the fused provider
2270 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2271 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002272 if (name == null) {
2273 throw new IllegalArgumentException("provider name must not be null");
2274 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002275
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002276 LocationProvider provider = mProvidersByName.get(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002277 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002278 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002279 }
2280
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002281 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002282 if (D) {
2283 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2284 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2285 + (record.mIsForegroundUid ? "foreground" : "background")
2286 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002287 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002288 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002289
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002290 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2291 if (oldRecord != null) {
2292 oldRecord.disposeLocked(false);
2293 }
2294
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002295 if (provider.isEnabled()) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002296 applyRequirementsLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002297 } else {
2298 // Notify the listener that updates are currently disabled
2299 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 }
David Christie0b837452013-07-29 16:02:13 -07002301 // Update the monitoring here just in case multiple location requests were added to the
2302 // same receiver (this request may be high power and the initial might not have been).
2303 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002304 }
2305
Nick Pellye0fd6932012-07-11 10:26:13 -07002306 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002307 public void removeUpdates(ILocationListener listener, PendingIntent intent,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002308 String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002309 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002310
Soonil Nagarkar68257742019-01-09 19:42:34 +00002311 final int pid = Binder.getCallingPid();
2312 final int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002313
Soonil Nagarkar68257742019-01-09 19:42:34 +00002314 synchronized (mLock) {
2315 Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
2316 packageName, null, false);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002317
Soonil Nagarkar68257742019-01-09 19:42:34 +00002318 // providers may use public location API's, need to clear identity
2319 long identity = Binder.clearCallingIdentity();
2320 try {
2321 removeUpdatesLocked(receiver);
2322 } finally {
2323 Binder.restoreCallingIdentity(identity);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002324 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002325 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002326 }
2327
Soonil Nagarkar68257742019-01-09 19:42:34 +00002328 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002329 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002330
2331 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2332 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2333 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002334 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002336 }
2337
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002338 receiver.updateMonitoring(false);
2339
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002340 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002341 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002342 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2343 if (oldRecords != null) {
2344 // Call dispose() on the obsolete update records.
2345 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002346 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002347 record.disposeLocked(false);
2348 }
2349 // Accumulate providers
2350 providers.addAll(oldRecords.keySet());
2351 }
2352
2353 // update provider
2354 for (String provider : providers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002355 applyRequirementsLocked(provider);
2356 }
2357 }
2358
2359 private void applyAllProviderRequirementsLocked() {
2360 for (LocationProvider p : mProviders) {
2361 applyRequirementsLocked(p.getName());
Dianne Hackbornc2293022013-02-06 23:14:49 -08002362 }
2363 }
2364
Nick Pellye0fd6932012-07-11 10:26:13 -07002365 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002366 public Location getLastLocation(LocationRequest request, String packageName) {
2367 if (D) Log.d(TAG, "getLastLocation: " + request);
2368 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002369 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07002370 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002371 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2372 request.getProvider());
2373 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002374
David Christieb870dbf2015-06-22 12:42:53 -07002375 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002376 final int uid = Binder.getCallingUid();
2377 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002378 try {
2379 if (mBlacklist.isBlacklisted(packageName)) {
gomo48f1a642017-11-10 20:35:46 -08002380 if (D) {
2381 Log.d(TAG, "not returning last loc for blacklisted app: " +
2382 packageName);
2383 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002384 return null;
2385 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002386
David Christieb870dbf2015-06-22 12:42:53 -07002387 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002388 if (D) {
2389 Log.d(TAG, "not returning last loc for no op app: " +
2390 packageName);
2391 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002392 return null;
2393 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002394
2395 synchronized (mLock) {
2396 // Figure out the provider. Either its explicitly request (deprecated API's),
2397 // or use the fused provider
2398 String name = request.getProvider();
2399 if (name == null) name = LocationManager.FUSED_PROVIDER;
2400 LocationProvider provider = mProvidersByName.get(name);
2401 if (provider == null) return null;
2402
2403 if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
2404
2405 Location location;
2406 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2407 // Make sure that an app with coarse permissions can't get frequent location
2408 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2409 location = mLastLocationCoarseInterval.get(name);
2410 } else {
2411 location = mLastLocation.get(name);
2412 }
2413 if (location == null) {
2414 return null;
2415 }
2416
2417 // Don't return stale location to apps with foreground-only location permission.
2418 String op = resolutionLevelToOpStr(allowedResolutionLevel);
2419 long locationAgeMs = SystemClock.elapsedRealtime() -
2420 location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2421 if ((locationAgeMs > mLastLocationMaxAgeMs)
2422 && (mAppOps.unsafeCheckOp(op, uid, packageName)
2423 == AppOpsManager.MODE_FOREGROUND)) {
2424 return null;
2425 }
2426
2427 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2428 Location noGPSLocation = location.getExtraLocation(
2429 Location.EXTRA_NO_GPS_LOCATION);
2430 if (noGPSLocation != null) {
2431 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
2432 }
2433 } else {
2434 return new Location(location);
2435 }
2436 }
2437 return null;
Victoria Leaseb711d572012-10-02 13:14:11 -07002438 } finally {
2439 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002440 }
2441 }
2442
Soonil Nagarkar68257742019-01-09 19:42:34 +00002443 /**
2444 * Provides an interface to inject and set the last location if location is not available
2445 * currently.
2446 *
2447 * This helps in cases where the product (Cars for example) has saved the last known location
2448 * before powering off. This interface lets the client inject the saved location while the GPS
2449 * chipset is getting its first fix, there by improving user experience.
2450 *
2451 * @param location - Location object to inject
2452 * @return true if update was successful, false if not
2453 */
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002454 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002455 public boolean injectLocation(Location location) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002456 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2457 "Location Hardware permission not granted to inject location");
2458 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2459 "Access Fine Location permission not granted to inject Location");
2460
2461 if (location == null) {
2462 if (D) {
2463 Log.d(TAG, "injectLocation(): called with null location");
2464 }
2465 return false;
2466 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002467 LocationProvider p = null;
2468 String provider = location.getProvider();
2469 if (provider != null) {
2470 p = mProvidersByName.get(provider);
2471 }
2472 if (p == null) {
2473 if (D) {
2474 Log.d(TAG, "injectLocation(): unknown provider");
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002475 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002476 return false;
2477 }
2478 synchronized (mLock) {
2479 if (!isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId)) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002480 if (D) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002481 Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002482 }
2483 return false;
2484 } else {
2485 // NOTE: If last location is already available, location is not injected. If
Soonil Nagarkar68257742019-01-09 19:42:34 +00002486 // provider's normal source (like a GPS chipset) have already provided an output,
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002487 // there is no need to inject this location.
2488 if (mLastLocation.get(provider) == null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002489 updateLastLocationLocked(location, provider);
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002490 } else {
2491 if (D) {
2492 Log.d(TAG, "injectLocation(): Location exists. Not updating");
2493 }
2494 return false;
2495 }
2496 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002497 }
2498 return true;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002499 }
2500
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002501 @Override
2502 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2503 String packageName) {
2504 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002505 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2506 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002507 checkPendingIntent(intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002508 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002509 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2510 request.getProvider());
gomo48f1a642017-11-10 20:35:46 -08002511 // Require that caller can manage given document
2512 boolean callerHasLocationHardwarePermission =
2513 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002514 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002515 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2516 callerHasLocationHardwarePermission);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002517
Soonil Nagarkar68257742019-01-09 19:42:34 +00002518 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002519
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002520 // geo-fence manager uses the public location API, need to clear identity
2521 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07002522 // TODO: http://b/23822629
2523 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08002524 // temporary measure until geofences work for secondary users
2525 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2526 return;
2527 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002528 long identity = Binder.clearCallingIdentity();
2529 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002530 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2531 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002532 } finally {
2533 Binder.restoreCallingIdentity(identity);
2534 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002535 }
2536
2537 @Override
2538 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002539 checkPendingIntent(intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002540 checkPackageName(packageName);
2541
2542 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2543
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002544 // geo-fence manager uses the public location API, need to clear identity
2545 long identity = Binder.clearCallingIdentity();
2546 try {
2547 mGeofenceManager.removeFence(geofence, intent);
2548 } finally {
2549 Binder.restoreCallingIdentity(identity);
2550 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002551 }
2552
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002553 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002554 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002555 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002556 return false;
2557 }
2558
Anil Admal75b9fd62018-11-28 11:22:50 -08002559 // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
2560 // measurements listeners.
2561 return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002562 }
2563
Nick Pellye0fd6932012-07-11 10:26:13 -07002564 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002565 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002566 mGnssStatusProvider.removeListener(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002567 }
2568
Nick Pellye0fd6932012-07-11 10:26:13 -07002569 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002570 public boolean addGnssMeasurementsListener(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002571 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002572 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002573 return false;
2574 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002575
Soonil Nagarkar68257742019-01-09 19:42:34 +00002576 synchronized (mLock) {
2577 Identity callerIdentity
2578 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002579 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002580 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002581 long identity = Binder.clearCallingIdentity();
2582 try {
2583 if (isThrottlingExemptLocked(callerIdentity)
2584 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002585 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002586 return mGnssMeasurementsProvider.addListener(listener,
2587 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002588 }
2589 } finally {
2590 Binder.restoreCallingIdentity(identity);
2591 }
2592
2593 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002594 }
destradaaea8a8a62014-06-23 18:19:03 -07002595 }
2596
2597 @Override
gomo226b7b72018-12-12 16:49:39 -08002598 public void injectGnssMeasurementCorrections(
2599 GnssMeasurementCorrections measurementCorrections, String packageName) {
2600 mContext.enforceCallingPermission(
2601 android.Manifest.permission.LOCATION_HARDWARE,
2602 "Location Hardware permission not granted to inject GNSS measurement corrections.");
2603 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2604 mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
2605 } else {
2606 Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
2607 }
2608 }
2609
2610 @Override
2611 public int getGnssCapabilities(String packageName) {
2612 mContext.enforceCallingPermission(
2613 android.Manifest.permission.LOCATION_HARDWARE,
2614 "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
2615 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2616 return -1;
2617 }
2618 return mGnssMeasurementsProvider.getGnssCapabilities();
2619 }
2620
2621 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002622 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002623 if (mGnssMeasurementsProvider == null) {
2624 return;
2625 }
2626
Soonil Nagarkar68257742019-01-09 19:42:34 +00002627 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002628 mGnssMeasurementsListeners.remove(listener.asBinder());
2629 mGnssMeasurementsProvider.removeListener(listener);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002630 }
destradaaea8a8a62014-06-23 18:19:03 -07002631 }
2632
2633 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002634 public boolean addGnssNavigationMessageListener(
2635 IGnssNavigationMessageListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002636 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002637 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002638 return false;
2639 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002640
Soonil Nagarkar68257742019-01-09 19:42:34 +00002641 synchronized (mLock) {
2642 Identity callerIdentity
2643 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002644 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002645 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002646 long identity = Binder.clearCallingIdentity();
2647 try {
2648 if (isThrottlingExemptLocked(callerIdentity)
2649 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002650 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002651 return mGnssNavigationMessageProvider.addListener(listener,
2652 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002653 }
2654 } finally {
2655 Binder.restoreCallingIdentity(identity);
2656 }
2657
2658 return true;
Wei Liu5241a4c2015-05-11 14:00:36 -07002659 }
destradaa4b3e3932014-07-21 18:01:47 -07002660 }
2661
2662 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002663 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2664 if (mGnssNavigationMessageProvider != null) {
2665 synchronized (mLock) {
2666 mGnssNavigationMessageListeners.remove(listener.asBinder());
2667 mGnssNavigationMessageProvider.removeListener(listener);
2668 }
2669 }
2670 }
2671
2672 @Override
2673 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002674 if (provider == null) {
2675 // throw NullPointerException to remain compatible with previous implementation
2676 throw new NullPointerException();
2677 }
Victoria Lease37425c32012-10-16 16:08:48 -07002678 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2679 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002681 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04002682 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
Maggieaa080f92018-01-04 15:35:11 -08002683 != PERMISSION_GRANTED)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002684 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2685 }
2686
Soonil Nagarkar68257742019-01-09 19:42:34 +00002687 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002688 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002689 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07002690
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002691 p.sendExtraCommand(command, extras);
2692 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002693 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002694 }
2695
Nick Pellye0fd6932012-07-11 10:26:13 -07002696 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002697 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002698 if (Binder.getCallingUid() != Process.myUid()) {
2699 throw new SecurityException(
2700 "calling sendNiResponse from outside of the system is not allowed");
2701 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002702 try {
2703 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002704 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002705 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002706 return false;
2707 }
2708 }
2709
Soonil Nagarkar68257742019-01-09 19:42:34 +00002710 /**
2711 * @return null if the provider does not exist
2712 * @throws SecurityException if the provider is not allowed to be
2713 * accessed by the caller
2714 */
Nick Pellye0fd6932012-07-11 10:26:13 -07002715 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002716 public ProviderProperties getProviderProperties(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07002717 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2718 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002719
Soonil Nagarkar68257742019-01-09 19:42:34 +00002720 LocationProvider p;
2721 synchronized (mLock) {
2722 p = mProvidersByName.get(provider);
2723 }
2724
2725 if (p == null) return null;
2726 return p.getProperties();
Jason Monkb71218a2015-06-17 14:44:39 -04002727 }
2728
Soonil Nagarkar68257742019-01-09 19:42:34 +00002729 /**
2730 * @return null if the provider does not exist
2731 * @throws SecurityException if the provider is not allowed to be
2732 * accessed by the caller
2733 */
Wei Wang980b7c22018-12-06 17:53:00 -08002734 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002735 public String getNetworkProviderPackage() {
2736 LocationProvider p;
2737 synchronized (mLock) {
2738 p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
2739 }
Wei Wang980b7c22018-12-06 17:53:00 -08002740
Soonil Nagarkar68257742019-01-09 19:42:34 +00002741 if (p == null) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002742 return null;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002743 }
2744 if (p.mProvider instanceof LocationProviderProxy) {
2745 return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
2746 }
2747 return null;
Maggie2a9409e2018-03-21 11:47:28 -07002748 }
2749
Maggie2a9409e2018-03-21 11:47:28 -07002750 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002751 public void setLocationControllerExtraPackage(String packageName) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002752 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2753 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002754 synchronized (mLock) {
2755 mLocationControllerExtraPackage = packageName;
2756 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002757 }
2758
2759 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002760 public String getLocationControllerExtraPackage() {
2761 synchronized (mLock) {
2762 return mLocationControllerExtraPackage;
2763 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002764 }
2765
2766 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002767 public void setLocationControllerExtraPackageEnabled(boolean enabled) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002768 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2769 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002770 synchronized (mLock) {
2771 mLocationControllerExtraPackageEnabled = enabled;
2772 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002773 }
2774
2775 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002776 public boolean isLocationControllerExtraPackageEnabled() {
2777 synchronized (mLock) {
2778 return mLocationControllerExtraPackageEnabled
2779 && (mLocationControllerExtraPackage != null);
2780 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002781 }
2782
Soonil Nagarkar68257742019-01-09 19:42:34 +00002783 /**
2784 * Returns the current location enabled/disabled status for a user
2785 *
2786 * @param userId the id of the user
2787 * @return true if location is enabled
2788 */
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002789 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002790 public boolean isLocationEnabledForUser(int userId) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002791 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar68257742019-01-09 19:42:34 +00002792 checkInteractAcrossUsersPermission(userId);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002793
Soonil Nagarkar68257742019-01-09 19:42:34 +00002794 long identity = Binder.clearCallingIdentity();
2795 try {
2796 synchronized (mLock) {
2797 final String allowedProviders = Settings.Secure.getStringForUser(
2798 mContext.getContentResolver(),
2799 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2800 userId);
2801 if (allowedProviders == null) {
2802 return false;
2803 }
2804 final List<String> providerList = Arrays.asList(allowedProviders.split(","));
2805 for (String provider : mRealProviders.keySet()) {
2806 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2807 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2808 continue;
2809 }
2810 if (providerList.contains(provider)) {
2811 return true;
2812 }
2813 }
2814 return false;
2815 }
2816 } finally {
2817 Binder.restoreCallingIdentity(identity);
2818 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002819 }
2820
Soonil Nagarkar68257742019-01-09 19:42:34 +00002821 /**
2822 * Enable or disable location for a user
2823 *
2824 * @param enabled true to enable location, false to disable location
2825 * @param userId the id of the user
2826 */
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002827 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002828 public void setLocationEnabledForUser(boolean enabled, int userId) {
Chad Brubaker90f391f2018-10-19 10:26:19 -07002829 mContext.enforceCallingOrSelfPermission(
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002830 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2831 "Requires WRITE_SECURE_SETTINGS permission");
Maggie2a9409e2018-03-21 11:47:28 -07002832
2833 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar68257742019-01-09 19:42:34 +00002834 checkInteractAcrossUsersPermission(userId);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002835
Soonil Nagarkar68257742019-01-09 19:42:34 +00002836 long identity = Binder.clearCallingIdentity();
2837 try {
2838 synchronized (mLock) {
2839 final Set<String> allRealProviders = mRealProviders.keySet();
2840 // Update all providers on device plus gps and network provider when disabling
2841 // location
2842 Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
2843 allProvidersSet.addAll(allRealProviders);
2844 // When disabling location, disable gps and network provider that could have been
2845 // enabled by location mode api.
2846 if (!enabled) {
2847 allProvidersSet.add(LocationManager.GPS_PROVIDER);
2848 allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002849 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002850 if (allProvidersSet.isEmpty()) {
2851 return;
2852 }
2853 // to ensure thread safety, we write the provider name with a '+' or '-'
2854 // and let the SettingsProvider handle it rather than reading and modifying
2855 // the list of enabled providers.
2856 final String prefix = enabled ? "+" : "-";
2857 StringBuilder locationProvidersAllowed = new StringBuilder();
2858 for (String provider : allProvidersSet) {
2859 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2860 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2861 continue;
2862 }
2863 locationProvidersAllowed.append(prefix);
2864 locationProvidersAllowed.append(provider);
2865 locationProvidersAllowed.append(",");
2866 }
2867 // Remove the trailing comma
2868 locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
2869 Settings.Secure.putStringForUser(
2870 mContext.getContentResolver(),
2871 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2872 locationProvidersAllowed.toString(),
2873 userId);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002874 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002875 } finally {
2876 Binder.restoreCallingIdentity(identity);
2877 }
Maggie2a9409e2018-03-21 11:47:28 -07002878 }
2879
Soonil Nagarkar68257742019-01-09 19:42:34 +00002880 /**
2881 * Returns the current enabled/disabled status of a location provider and user
2882 *
2883 * @param providerName name of the provider
2884 * @param userId the id of the user
2885 * @return true if the provider exists and is enabled
2886 */
Maggie2a9409e2018-03-21 11:47:28 -07002887 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002888 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002889 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar68257742019-01-09 19:42:34 +00002890 checkInteractAcrossUsersPermission(userId);
2891
2892 if (!isLocationEnabledForUser(userId)) {
2893 return false;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002894 }
2895
Maggie2a9409e2018-03-21 11:47:28 -07002896 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2897 // so we discourage its use
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002898 if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002899
Soonil Nagarkar68257742019-01-09 19:42:34 +00002900 long identity = Binder.clearCallingIdentity();
2901 try {
2902 LocationProvider provider;
2903 synchronized (mLock) {
2904 provider = mProvidersByName.get(providerName);
2905 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002906 return provider != null && provider.isEnabled();
Soonil Nagarkar68257742019-01-09 19:42:34 +00002907 } finally {
2908 Binder.restoreCallingIdentity(identity);
2909 }
Maggie2a9409e2018-03-21 11:47:28 -07002910 }
2911
Soonil Nagarkar68257742019-01-09 19:42:34 +00002912 /**
2913 * Enable or disable a single location provider.
2914 *
2915 * @param provider name of the provider
2916 * @param enabled true to enable the provider. False to disable the provider
2917 * @param userId the id of the user to set
2918 * @return true if the value was set, false on errors
2919 */
Maggie2a9409e2018-03-21 11:47:28 -07002920 @Override
2921 public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002922 return false;
Maggieaa080f92018-01-04 15:35:11 -08002923 }
2924
Soonil Nagarkar68257742019-01-09 19:42:34 +00002925 /**
2926 * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
2927 * current user id
2928 *
2929 * @param userId the user id to get or set value
2930 */
2931 private void checkInteractAcrossUsersPermission(int userId) {
2932 int uid = Binder.getCallingUid();
2933 if (UserHandle.getUserId(uid) != userId) {
2934 if (ActivityManager.checkComponentPermission(
2935 android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
2936 != PERMISSION_GRANTED) {
2937 throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
2938 }
2939 }
2940 }
2941
2942 /**
2943 * Returns "true" if the UID belongs to a bound location provider.
2944 *
2945 * @param uid the uid
2946 * @return true if uid belongs to a bound location provider
2947 */
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002948 private boolean isUidALocationProvider(int uid) {
2949 if (uid == Process.SYSTEM_UID) {
2950 return true;
2951 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002952 if (mGeocodeProvider != null) {
2953 if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true;
2954 }
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002955 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002956 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002957 }
2958 return false;
2959 }
2960
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002961 private void checkCallerIsProvider() {
2962 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
Maggieaa080f92018-01-04 15:35:11 -08002963 == PERMISSION_GRANTED) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002964 return;
2965 }
2966
2967 // Previously we only used the INSTALL_LOCATION_PROVIDER
2968 // check. But that is system or signature
2969 // protection level which is not flexible enough for
2970 // providers installed oustide the system image. So
2971 // also allow providers with a UID matching the
2972 // currently bound package name
Soonil Nagarkar68257742019-01-09 19:42:34 +00002973
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002974 if (isUidALocationProvider(Binder.getCallingUid())) {
2975 return;
2976 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002977
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002978 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2979 "or UID of a currently bound location provider");
2980 }
2981
Soonil Nagarkar68257742019-01-09 19:42:34 +00002982 /**
2983 * Returns true if the given package belongs to the given uid.
2984 */
David Christie1f141c12014-05-14 15:11:15 -07002985 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002986 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002987 return false;
2988 }
David Christie1f141c12014-05-14 15:11:15 -07002989 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2990 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002991 return false;
2992 }
David Christie1f141c12014-05-14 15:11:15 -07002993 for (String name : packageNames) {
2994 if (packageName.equals(name)) {
2995 return true;
2996 }
2997 }
2998 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002999 }
3000
Nick Pellye0fd6932012-07-11 10:26:13 -07003001 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05003002 public void reportLocation(Location location, boolean passive) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003003 checkCallerIsProvider();
3004
3005 if (!location.isComplete()) {
3006 Log.w(TAG, "Dropping incomplete location: " + location);
3007 return;
3008 }
3009
3010 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
3011 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
3012 m.arg1 = (passive ? 1 : 0);
3013 mLocationHandler.sendMessageAtFrontOfQueue(m);
Mike Lockwood4e50b782009-04-03 08:24:43 -07003014 }
3015
Soonil Nagarkar68257742019-01-09 19:42:34 +00003016
Laurent Tu75defb62012-11-01 16:21:52 -07003017 private static boolean shouldBroadcastSafe(
3018 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003019 // Always broadcast the first update
3020 if (lastLoc == null) {
3021 return true;
3022 }
3023
Nick Pellyf1be6862012-05-15 10:53:42 -07003024 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003025 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07003026 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
3027 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003028 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003029 return false;
3030 }
3031
3032 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003033 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 if (minDistance > 0.0) {
3035 if (loc.distanceTo(lastLoc) <= minDistance) {
3036 return false;
3037 }
3038 }
3039
Laurent Tu75defb62012-11-01 16:21:52 -07003040 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003041 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07003042 return false;
3043 }
3044
3045 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003046 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003047 }
3048
Soonil Nagarkar68257742019-01-09 19:42:34 +00003049 private void handleLocationChangedLocked(Location location, boolean passive) {
3050 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003051 long now = SystemClock.elapsedRealtime();
Soonil Nagarkar68257742019-01-09 19:42:34 +00003052 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
Laurent Tu60ec50a2012-10-04 17:00:10 -07003053 // Skip if the provider is unknown.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003054 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003055 if (p == null) return;
Soonil Nagarkar68257742019-01-09 19:42:34 +00003056 updateLastLocationLocked(location, provider);
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003057 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003058 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07003059 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003060 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
3061 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07003062 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003063
David Christie1b9b7b12013-04-15 15:31:11 -07003064 // Update last known coarse interval location if enough time has passed.
3065 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
3066 if (lastLocationCoarseInterval == null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003067 lastLocationCoarseInterval = new Location(location);
David Christie1b9b7b12013-04-15 15:31:11 -07003068 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
3069 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003070 long timeDiffNanos = location.getElapsedRealtimeNanos()
David Christie1b9b7b12013-04-15 15:31:11 -07003071 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
3072 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003073 lastLocationCoarseInterval.set(location);
David Christie1b9b7b12013-04-15 15:31:11 -07003074 }
3075 // Don't ever return a coarse location that is more recent than the allowed update
3076 // interval (i.e. don't allow an app to keep registering and unregistering for
3077 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003078 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07003079 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3080
Laurent Tu60ec50a2012-10-04 17:00:10 -07003081 // Skip if there are no UpdateRecords for this provider.
3082 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
3083 if (records == null || records.size() == 0) return;
3084
Victoria Lease09016ab2012-09-16 12:33:15 -07003085 // Fetch coarse location
3086 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07003087 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003088 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
3089 }
3090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091 // Fetch latest status update time
3092 long newStatusUpdateTime = p.getStatusUpdateTime();
3093
David Christie2ff96af2014-01-30 16:09:37 -08003094 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 Bundle extras = new Bundle();
3096 int status = p.getStatus(extras);
3097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003098 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003099 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07003100
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003101 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003102 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003104 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003105
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003106 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
3107 if (!isCurrentProfile(receiverUserId)
3108 && !isUidALocationProvider(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003109 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003110 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003111 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003112 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003113 }
3114 continue;
3115 }
3116
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003117 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003118 if (D) {
3119 Log.d(TAG, "skipping loc update for blacklisted app: " +
3120 receiver.mIdentity.mPackageName);
3121 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003122 continue;
3123 }
3124
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003125 if (!reportLocationAccessNoThrow(
3126 receiver.mIdentity.mPid,
3127 receiver.mIdentity.mUid,
3128 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003129 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003130 if (D) {
3131 Log.d(TAG, "skipping loc update for no op app: " +
3132 receiver.mIdentity.mPackageName);
3133 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003134 continue;
3135 }
3136
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003137 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003138 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3139 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003140 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07003141 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003142 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003143 if (notifyLocation != null) {
3144 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07003145 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003146 if (lastLoc == null) {
3147 lastLoc = new Location(notifyLocation);
3148 r.mLastFixBroadcast = lastLoc;
3149 } else {
3150 lastLoc.set(notifyLocation);
3151 }
3152 if (!receiver.callLocationChangedLocked(notifyLocation)) {
3153 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
3154 receiverDead = true;
3155 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003156 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 }
3158 }
3159
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003160 // TODO: location provider status callbacks have been disabled and deprecated, and are
3161 // guarded behind this setting now. should be removed completely post-Q
3162 if (Settings.Global.getInt(mContext.getContentResolver(),
3163 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
3164 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3165 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003166 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003168 r.mLastStatusBroadcast = newStatusUpdateTime;
3169 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
3170 receiverDead = true;
3171 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3172 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003173 }
3174 }
3175
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003176 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003177 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003178 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003179 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003180 }
3181 deadUpdateRecords.add(r);
3182 }
3183 // track dead receivers
3184 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003185 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003186 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003187 }
3188 if (!deadReceivers.contains(receiver)) {
3189 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 }
3191 }
3192 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003193
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003194 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003196 for (Receiver receiver : deadReceivers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003197 removeUpdatesLocked(receiver);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003198 }
3199 }
3200 if (deadUpdateRecords != null) {
3201 for (UpdateRecord r : deadUpdateRecords) {
3202 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003204 applyRequirementsLocked(provider);
Victoria Lease8b38b292012-12-04 15:04:43 -08003205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003206 }
3207
Soonil Nagarkar68257742019-01-09 19:42:34 +00003208 /**
3209 * Updates last location with the given location
3210 *
3211 * @param location new location to update
3212 * @param provider Location provider to update for
3213 */
3214 private void updateLastLocationLocked(Location location, String provider) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003215 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3216 Location lastNoGPSLocation;
3217 Location lastLocation = mLastLocation.get(provider);
3218 if (lastLocation == null) {
3219 lastLocation = new Location(provider);
3220 mLastLocation.put(provider, lastLocation);
3221 } else {
3222 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3223 if (noGPSLocation == null && lastNoGPSLocation != null) {
3224 // New location has no no-GPS location: adopt last no-GPS location. This is set
3225 // directly into location because we do not want to notify COARSE clients.
3226 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3227 }
3228 }
3229 lastLocation.set(location);
3230 }
3231
Soonil Nagarkar68257742019-01-09 19:42:34 +00003232 private class LocationWorkerHandler extends Handler {
3233 public LocationWorkerHandler(Looper looper) {
3234 super(looper, null, true);
3235 }
3236
3237 @Override
3238 public void handleMessage(Message msg) {
3239 switch (msg.what) {
3240 case MSG_LOCATION_CHANGED:
3241 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
3242 break;
3243 }
3244 }
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003245 }
3246
Soonil Nagarkar68257742019-01-09 19:42:34 +00003247 private boolean isMockProvider(String provider) {
3248 synchronized (mLock) {
3249 return mMockProviders.containsKey(provider);
3250 }
3251 }
3252
3253 private void handleLocationChanged(Location location, boolean passive) {
3254 // create a working copy of the incoming Location so that the service can modify it without
3255 // disturbing the caller's copy
3256 Location myLocation = new Location(location);
3257 String provider = myLocation.getProvider();
3258
3259 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
3260 // bit if location did not come from a mock provider because passive/fused providers can
3261 // forward locations from mock providers, and should not grant them legitimacy in doing so.
3262 if (!myLocation.isFromMockProvider() && isMockProvider(provider)) {
3263 myLocation.setIsFromMockProvider(true);
3264 }
3265
3266 synchronized (mLock) {
3267 if (!passive) {
3268 // notify passive provider of the new location
3269 mPassiveProvider.updateLocation(myLocation);
3270 }
3271 handleLocationChangedLocked(myLocation, passive);
3272 }
3273 }
3274
3275 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
3276 @Override
3277 public void onPackageDisappeared(String packageName, int reason) {
3278 // remove all receivers associated with this package name
3279 synchronized (mLock) {
3280 ArrayList<Receiver> deadReceivers = null;
3281
3282 for (Receiver receiver : mReceivers.values()) {
3283 if (receiver.mIdentity.mPackageName.equals(packageName)) {
3284 if (deadReceivers == null) {
3285 deadReceivers = new ArrayList<>();
3286 }
3287 deadReceivers.add(receiver);
3288 }
3289 }
3290
3291 // perform removal outside of mReceivers loop
3292 if (deadReceivers != null) {
3293 for (Receiver receiver : deadReceivers) {
3294 removeUpdatesLocked(receiver);
3295 }
3296 }
3297 }
3298 }
3299 };
3300
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 // Geocoder
3302
Nick Pellye0fd6932012-07-11 10:26:13 -07003303 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003304 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003305 return mGeocodeProvider != null;
3306 }
3307
Nick Pellye0fd6932012-07-11 10:26:13 -07003308 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003310 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003311 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003312 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3313 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003314 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003315 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003316 }
3317
Mike Lockwooda55c3212009-04-15 11:10:11 -04003318
Nick Pellye0fd6932012-07-11 10:26:13 -07003319 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003321 double lowerLeftLatitude, double lowerLeftLongitude,
3322 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003323 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003324
3325 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003326 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3327 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3328 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003330 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003331 }
3332
3333 // Mock Providers
3334
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003335 private boolean canCallerAccessMockLocation(String opPackageName) {
3336 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3337 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003338 }
3339
Nick Pellye0fd6932012-07-11 10:26:13 -07003340 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003341 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003342 if (!canCallerAccessMockLocation(opPackageName)) {
3343 return;
3344 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003345
Mike Lockwooda4903f22010-02-17 06:42:23 -05003346 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
3347 throw new IllegalArgumentException("Cannot mock the passive location provider");
3348 }
3349
Soonil Nagarkar68257742019-01-09 19:42:34 +00003350 long identity = Binder.clearCallingIdentity();
3351 synchronized (mLock) {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003352 // remove the real provider if we are replacing GPS or network provider
3353 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07003354 || LocationManager.NETWORK_PROVIDER.equals(name)
3355 || LocationManager.FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003356 LocationProvider p = mProvidersByName.get(name);
Mike Lockwoodd03ff942010-02-09 08:46:14 -05003357 if (p != null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003358 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003359 }
3360 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003361 addTestProviderLocked(name, properties);
3362 }
3363 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 }
3365
Soonil Nagarkar68257742019-01-09 19:42:34 +00003366 private void addTestProviderLocked(String name, ProviderProperties properties) {
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003367 if (mProvidersByName.get(name) != null) {
3368 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
3369 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003370
3371 LocationProvider provider = new LocationProvider(name);
3372 MockProvider mockProvider = new MockProvider(provider, properties);
3373
Soonil Nagarkar68257742019-01-09 19:42:34 +00003374 addProviderLocked(provider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003375 mMockProviders.put(name, mockProvider);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003376 mLastLocation.put(name, null);
3377 mLastLocationCoarseInterval.put(name, null);
3378 }
3379
Nick Pellye0fd6932012-07-11 10:26:13 -07003380 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003381 public void removeTestProvider(String provider, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003382 if (!canCallerAccessMockLocation(opPackageName)) {
3383 return;
3384 }
3385
Soonil Nagarkar68257742019-01-09 19:42:34 +00003386 synchronized (mLock) {
You Kima6d0b6f2012-10-28 03:58:44 +09003387 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003388 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003389 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3390 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003391
Soonil Nagarkar68257742019-01-09 19:42:34 +00003392 long identity = Binder.clearCallingIdentity();
3393 try {
3394 removeProviderLocked(mProvidersByName.get(provider));
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003395
Soonil Nagarkar68257742019-01-09 19:42:34 +00003396 // reinstate real provider if available
3397 LocationProvider realProvider = mRealProviders.get(provider);
3398 if (realProvider != null) {
3399 addProviderLocked(realProvider);
3400 }
3401 mLastLocation.put(provider, null);
3402 mLastLocationCoarseInterval.put(provider, null);
3403 } finally {
3404 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003405 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 }
3408
Nick Pellye0fd6932012-07-11 10:26:13 -07003409 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003410 public void setTestProviderLocation(String provider, Location loc, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003411 if (!canCallerAccessMockLocation(opPackageName)) {
3412 return;
3413 }
3414
Soonil Nagarkar68257742019-01-09 19:42:34 +00003415 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003416 MockProvider mockProvider = mMockProviders.get(provider);
3417 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003418 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3419 }
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003420
Soonil Nagarkar68257742019-01-09 19:42:34 +00003421 // Ensure that the location is marked as being mock. There's some logic to do this in
3422 // handleLocationChanged(), but it fails if loc has the wrong provider (bug 33091107).
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003423 Location mock = new Location(loc);
3424 mock.setIsFromMockProvider(true);
3425
3426 if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003427 // The location has an explicit provider that is different from the mock provider
3428 // name. The caller may be trying to fool us via bug 33091107.
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003429 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3430 provider + "!=" + loc.getProvider());
3431 }
3432
Soonil Nagarkar68257742019-01-09 19:42:34 +00003433 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
3434 long identity = Binder.clearCallingIdentity();
3435 try {
3436 mockProvider.setLocation(mock);
3437 } finally {
3438 Binder.restoreCallingIdentity(identity);
3439 }
3440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003441 }
3442
Nick Pellye0fd6932012-07-11 10:26:13 -07003443 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003444 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003445 if (!canCallerAccessMockLocation(opPackageName)) {
3446 return;
3447 }
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003448
Soonil Nagarkar68257742019-01-09 19:42:34 +00003449 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003450 MockProvider mockProvider = mMockProviders.get(provider);
3451 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003452 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3453 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003454 long identity = Binder.clearCallingIdentity();
3455 try {
3456 mockProvider.setEnabled(enabled);
3457 } finally {
3458 Binder.restoreCallingIdentity(identity);
3459 }
3460 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003461 }
3462
Nick Pellye0fd6932012-07-11 10:26:13 -07003463 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003464 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
Soonil Nagarkar68257742019-01-09 19:42:34 +00003465 String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003466 if (!canCallerAccessMockLocation(opPackageName)) {
3467 return;
3468 }
3469
Soonil Nagarkar68257742019-01-09 19:42:34 +00003470 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003471 MockProvider mockProvider = mMockProviders.get(provider);
3472 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003473 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3474 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003475 mockProvider.setStatus(status, extras, updateTime);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003476 }
3477 }
3478
3479 private void log(String log) {
3480 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3481 Slog.d(TAG, log);
3482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003483 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003484
3485 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003487 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003488
Soonil Nagarkar68257742019-01-09 19:42:34 +00003489 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003490 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3491 if (mGnssMetricsProvider != null) {
3492 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3493 }
3494 return;
3495 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003496 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003497 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003498 for (Receiver receiver : mReceivers.values()) {
3499 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003500 }
David Christie2ff96af2014-01-30 16:09:37 -08003501 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003502 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3503 pw.println(" " + entry.getKey() + ":");
3504 for (UpdateRecord record : entry.getValue()) {
3505 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 }
3507 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003508 pw.println(" Active GnssMeasurement Listeners:");
3509 for (Identity identity : mGnssMeasurementsListeners.values()) {
3510 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3511 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3512 }
3513 pw.println(" Active GnssNavigationMessage Listeners:");
3514 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3515 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3516 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3517 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003518 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003519 for (LocationProvider provider : mProviders) {
3520 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003521 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003522 + ((LocationProviderProxy) provider.mProvider)
3523 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003524 }
3525 }
David Christie2ff96af2014-01-30 16:09:37 -08003526 pw.println(" Historical Records by Provider:");
3527 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3528 : mRequestStatistics.statistics.entrySet()) {
3529 PackageProviderKey key = entry.getKey();
3530 PackageStatistics stats = entry.getValue();
3531 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3532 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003533 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003534 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3535 String provider = entry.getKey();
3536 Location location = entry.getValue();
3537 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003539
David Christie1b9b7b12013-04-15 15:31:11 -07003540 pw.println(" Last Known Locations Coarse Intervals:");
3541 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3542 String provider = entry.getKey();
3543 Location location = entry.getValue();
3544 pw.println(" " + provider + ": " + location);
3545 }
3546
Nick Pellye0fd6932012-07-11 10:26:13 -07003547 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003548
Nick Pelly4035f5a2012-08-17 14:43:49 -07003549 pw.append(" ");
3550 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003551 if (mMockProviders.size() > 0) {
3552 pw.println(" Mock Providers:");
3553 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003554 i.getValue().dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 }
3556 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003557
Wei Wang980b7c22018-12-06 17:53:00 -08003558 if (mLocationControllerExtraPackage != null) {
3559 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
3560 + " enabled: " + mLocationControllerExtraPackageEnabled);
3561 }
3562
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003563 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3564 pw.println(" Throttling Whitelisted Packages:");
3565 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3566 pw.println(" " + packageName);
3567 }
3568 }
3569
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003570 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003571 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003572
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003573 if (args.length > 0 && "short".equals(args[0])) {
3574 return;
3575 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003576 for (LocationProvider provider : mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003577 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003578 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003579 if (mGnssBatchingInProgress) {
3580 pw.println(" GNSS batching in progress");
3581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003582 }
3583 }
3584}