blob: 5cea56ebf2fc723491de7ddf3efabf70dcd2051f [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;
Maggieaa080f92018-01-04 15:35:11 -080067import android.os.PowerManager;
68import android.os.Process;
69import android.os.RemoteException;
70import android.os.SystemClock;
71import android.os.UserHandle;
72import android.os.UserManager;
73import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000074import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080075import android.provider.Settings;
76import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080077import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080078import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080079import android.util.EventLog;
80import android.util.Log;
81import android.util.Slog;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -070082
destradaaea8a8a62014-06-23 18:19:03 -070083import com.android.internal.content.PackageMonitor;
84import com.android.internal.location.ProviderProperties;
85import com.android.internal.location.ProviderRequest;
86import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070087import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060088import com.android.internal.util.DumpUtils;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -080089import com.android.internal.util.Preconditions;
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;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800120import java.util.concurrent.Callable;
121import java.util.concurrent.CopyOnWriteArrayList;
122import java.util.concurrent.ExecutionException;
123import java.util.concurrent.Executors;
124import java.util.concurrent.FutureTask;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
126/**
127 * The service class that manages LocationProviders and issues location
128 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800130public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800132 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700133
Olivier Gaillard7a222662017-11-20 16:07:24 +0000134 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135
Victoria Lease37425c32012-10-16 16:08:48 -0700136 // Location resolution level: no location data whatsoever
137 private static final int RESOLUTION_LEVEL_NONE = 0;
138 // Location resolution level: coarse location data only
139 private static final int RESOLUTION_LEVEL_COARSE = 1;
140 // Location resolution level: fine location data
141 private static final int RESOLUTION_LEVEL_FINE = 2;
142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700144 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400145 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700146 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
147
148 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700149 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700150 private static final String FUSED_LOCATION_SERVICE_ACTION =
151 "com.android.location.service.FusedLocationProvider";
152
153 private static final int MSG_LOCATION_CHANGED = 1;
154
David Christie1b9b7b12013-04-15 15:31:11 -0700155 private static final long NANOS_PER_MILLI = 1000000L;
156
David Christie0b837452013-07-29 16:02:13 -0700157 // The maximum interval a location request can have and still be considered "high power".
158 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
159
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700160 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800161 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700162
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800163 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800164 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800165
Wei Wangdd070f22018-06-21 11:29:40 -0700166 // Default value for maximum age of last location returned to applications with foreground-only
167 // location permissions.
168 private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
169
Nick Pellyf1be6862012-05-15 10:53:42 -0700170 // Location Providers may sometimes deliver location updates
171 // slightly faster that requested - provide grace period so
172 // we don't unnecessarily filter events that are otherwise on
173 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700175
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700176 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
177
178 private final Context mContext;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800179 private AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700180
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700181 // --- fields below are final after systemRunning() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700182 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 private GeofenceManager mGeofenceManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700184 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700185 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800186 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700187 private UserManager mUserManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700188 private GeocoderProxy mGeocodeProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800189 private GnssStatusListenerHelper mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700190 private INetInitiatedListener mNetInitiatedListener;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800191 private final Handler mHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700192 private PassiveProvider mPassiveProvider; // track passive provider for special cases
193 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800194 private GnssMeasurementsProvider mGnssMeasurementsProvider;
195 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Wei Wang980b7c22018-12-06 17:53:00 -0800196 private String mLocationControllerExtraPackage;
197 private boolean mLocationControllerExtraPackageEnabled;
Wei Liu5241a4c2015-05-11 14:00:36 -0700198 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700199
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 Nagarkarb2fcddd2019-01-03 15:20:06 -0800208 private final CopyOnWriteArrayList<LocationProvider> mProviders =
209 new CopyOnWriteArrayList<>();
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 Nagarkarb2fcddd2019-01-03 15:20:06 -0800235 private final CopyOnWriteArrayList<LocationProviderProxy> mProxyProviders =
236 new CopyOnWriteArrayList<>();
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
Lifu Tang9363b942016-02-16 18:07:00 -0800249 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800250
Siddharth Raybb608c82017-03-16 11:33:34 -0700251 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700252
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700253 private GnssBatchingProvider mGnssBatchingProvider;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800254 private IBatchedLocationCallback mGnssBatchingCallback;
255 private LinkedCallback mGnssBatchingDeathCallback;
256 private boolean mGnssBatchingInProgress = false;
257
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700258 public LocationManagerService(Context context) {
259 super();
260 mContext = context;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800261 mHandler = BackgroundThread.getHandler();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800262
Svet Ganovadc1cf42015-06-15 16:36:24 -0700263 // Let the package manager query which are the default location
264 // providers as they get certain permissions granted by default.
265 PackageManagerInternal packageManagerInternal = LocalServices.getService(
266 PackageManagerInternal.class);
267 packageManagerInternal.setLocationPackagesProvider(
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700268 userId -> mContext.getResources().getStringArray(
269 com.android.internal.R.array.config_locationProviderPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700270
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700271 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700272 }
273
Svetoslav Ganova0027152013-06-25 14:59:53 -0700274 public void systemRunning() {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800275 runInternal(this::initialize);
276 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700277
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800278 private void initialize() {
279 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800280
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800281 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
282 mPackageManager = mContext.getPackageManager();
283 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
284 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
Victoria Lease5cd731a2012-12-19 15:04:21 -0800285
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800286 // prepare mHandler's dependents
287 mLocationFudger = new LocationFudger(mContext, mHandler);
288 mBlacklist = new LocationBlacklist(mContext, mHandler);
289 mBlacklist.init();
290 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800291
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800292 mAppOps.startWatchingMode(
293 AppOpsManager.OP_COARSE_LOCATION,
294 null,
295 AppOpsManager.WATCH_FOREGROUND_CHANGES,
296 new AppOpsManager.OnOpChangedInternalListener() {
297 public void onOpChanged(int op, String packageName) {
298 mHandler.post(() -> onAppOpChanged());
299 }
300 });
Victoria Lease5cd731a2012-12-19 15:04:21 -0800301
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800302 mPackageManager.addOnPermissionsChangeListener(
303 uid -> runInternal(this::onPermissionsChanged));
Victoria Lease5cd731a2012-12-19 15:04:21 -0800304
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800305 mActivityManager.addOnUidImportanceListener(
306 (uid, importance) -> mHandler.post(
307 () -> onUidImportanceChanged(uid, importance)),
308 FOREGROUND_IMPORTANCE_CUTOFF);
Dianne Hackbornc2293022013-02-06 23:14:49 -0800309
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800310 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
311 updateUserProfiles(mCurrentUserId);
David Christieb870dbf2015-06-22 12:42:53 -0700312
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800313 updateBackgroundThrottlingWhitelist();
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800314
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800315 // prepare providers
316 loadProvidersLocked();
317 updateProvidersSettings();
318 for (LocationProvider provider : mProviders) {
319 applyRequirements(provider.getName());
Victoria Lease5cd731a2012-12-19 15:04:21 -0800320 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700321
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700322 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700323 mContext.getContentResolver().registerContentObserver(
Laurent Tu75defb62012-11-01 16:21:52 -0700324 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800325 new ContentObserver(mHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800326 @Override
327 public void onChange(boolean selfChange) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800328 onProviderAllowedChanged();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800329 }
330 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800331 mContext.getContentResolver().registerContentObserver(
332 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
333 true,
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800334 new ContentObserver(mHandler) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800335 @Override
336 public void onChange(boolean selfChange) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800337 onBackgroundThrottleIntervalChanged();
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800338 }
339 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800340 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800341 Settings.Global.getUriFor(
342 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
343 true,
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800344 new ContentObserver(mHandler) {
gomo48f1a642017-11-10 20:35:46 -0800345 @Override
346 public void onChange(boolean selfChange) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800347 onBackgroundThrottleWhitelistChanged();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800348 }
gomo48f1a642017-11-10 20:35:46 -0800349 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700350
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800351 new PackageMonitor() {
352 @Override
353 public void onPackageDisappeared(String packageName, int reason) {
354 LocationManagerService.this.onPackageDisappeared(packageName);
355 }
356 }.register(mContext, mHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700357
Victoria Lease38389b62012-09-30 11:44:22 -0700358 // listen for user change
359 IntentFilter intentFilter = new IntentFilter();
360 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700361 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
362 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700363
364 mContext.registerReceiverAsUser(new BroadcastReceiver() {
365 @Override
366 public void onReceive(Context context, Intent intent) {
367 String action = intent.getAction();
368 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
369 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
Amith Yamasanib27528d2014-06-05 15:02:10 -0700370 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
371 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
372 updateUserProfiles(mCurrentUserId);
Victoria Lease38389b62012-09-30 11:44:22 -0700373 }
374 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800375 }, UserHandle.ALL, intentFilter, null, mHandler);
376 }
377
378 // will block until completion and propagate exceptions, and thus should be used from binder
379 // threads, particuarily binder threads from components that sit above LMS (ie, not location
380 // providers).
381 private void runFromBinderBlocking(Runnable runnable) throws RemoteException {
382 runFromBinderBlocking(Executors.callable(runnable));
383 }
384
385 // will block until completion and propagate exceptions, and thus should be used from binder
386 // threads, particuarily binder threads from components that sit above LMS (ie, not location
387 // providers).
388 private <T> T runFromBinderBlocking(Callable<T> callable) throws RemoteException {
389 FutureTask<T> task = new FutureTask<>(callable);
390 long identity = Binder.clearCallingIdentity();
391 try {
392 runInternal(task);
393 } finally {
394 Binder.restoreCallingIdentity(identity);
395 }
396 try {
397 return task.get();
398 } catch (ExecutionException e) {
399 // binder calls can handle 3 types of exceptions, runtimeexception and error (which can
400 // be thrown any time), and remote exception. we transfer all of these exceptions from
401 // the execution thread to the binder thread so that they may propagate normally. note
402 // that we are loosing some context in doing so (losing the stack trace from the binder
403 // thread).
404 if (e.getCause() instanceof RemoteException) {
405 throw (RemoteException) e.getCause();
406 } else if (e.getCause() instanceof RuntimeException) {
407 throw (RuntimeException) e.getCause();
408 } else if (e.getCause() instanceof Error) {
409 throw (Error) e.getCause();
410 }
411
412 // callers should not throw checked exceptions
413 Log.wtf(TAG, "caller threw checked exception", e);
414 throw new UnsupportedOperationException(e);
415 } catch (InterruptedException e) {
416 throw new RemoteException("Binder call interrupted", e, true, true);
417 }
418 }
419
420 // will return immediately and will not propagate exceptions. should be used for non-binder work
421 // that needs to be shifted onto the location thread, primarily listeners that do not support
422 // running on arbitrary threads.
423 private void runInternal(Runnable runnable) {
424 // it would be a better use of resources to use locks to manage cross thread access to
425 // various pieces on information. however, the history of the location package has mostly
426 // shown that this is difficult to maintain in a multi-dev environment, and tends to always
427 // lead towards the use of uber-locks and deadlocks. using a single thread to run everything
428 // is more understandable for most devs, and seems less likely to result in future bugs
429 if (Looper.myLooper() == mHandler.getLooper()) {
430 runnable.run();
431 } else {
432 mHandler.post(runnable);
433 }
434 }
435
436 private void onAppOpChanged() {
437 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
438 for (Receiver receiver : mReceivers.values()) {
439 receiver.updateMonitoring(true);
440 }
441 for (LocationProvider p : mProviders) {
442 applyRequirements(p.getName());
443 }
444 }
445
446 private void onPermissionsChanged() {
447 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
448 for (LocationProvider p : mProviders) {
449 applyRequirements(p.getName());
450 }
451 }
452
453 private void onProviderAllowedChanged() {
454 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
455 updateProvidersSettings();
456 }
457
458 private void onPackageDisappeared(String packageName) {
459 ArrayList<Receiver> deadReceivers = null;
460
461 for (Receiver receiver : mReceivers.values()) {
462 if (receiver.mIdentity.mPackageName.equals(packageName)) {
463 if (deadReceivers == null) {
464 deadReceivers = new ArrayList<>();
465 }
466 deadReceivers.add(receiver);
467 }
468 }
469
470 // perform removal outside of mReceivers loop
471 if (deadReceivers != null) {
472 for (Receiver receiver : deadReceivers) {
473 removeUpdates(receiver);
474 }
475 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700476 }
477
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700478 private void onUidImportanceChanged(int uid, int importance) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800479 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700480 boolean foreground = isImportanceForeground(importance);
481 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800482 for (Entry<String, ArrayList<UpdateRecord>> entry
483 : mRecordsByProvider.entrySet()) {
484 String provider = entry.getKey();
485 for (UpdateRecord record : entry.getValue()) {
486 if (record.mReceiver.mIdentity.mUid == uid
487 && record.mIsForegroundUid != foreground) {
gomo48f1a642017-11-10 20:35:46 -0800488 if (D) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800489 Log.d(TAG, "request from uid " + uid + " is now "
gomo48f1a642017-11-10 20:35:46 -0800490 + (foreground ? "foreground" : "background)"));
491 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800492 record.updateForeground(foreground);
493
494 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
495 affectedProviders.add(provider);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700496 }
497 }
498 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800499 }
500 for (String provider : affectedProviders) {
501 applyRequirements(provider);
502 }
Anil Admal75b9fd62018-11-28 11:22:50 -0800503
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800504 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
505 Identity callerIdentity = entry.getValue();
506 if (callerIdentity.mUid == uid) {
507 if (D) {
508 Log.d(TAG, "gnss measurements listener from uid " + uid
509 + " is now " + (foreground ? "foreground" : "background)"));
510 }
511 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
512 mGnssMeasurementsProvider.addListener(
513 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
514 callerIdentity.mUid, callerIdentity.mPackageName);
515 } else {
516 mGnssMeasurementsProvider.removeListener(
517 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
518 }
519 }
520 }
521
522 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
523 Identity callerIdentity = entry.getValue();
524 if (callerIdentity.mUid == uid) {
525 if (D) {
526 Log.d(TAG, "gnss navigation message listener from uid "
527 + uid + " is now "
528 + (foreground ? "foreground" : "background)"));
529 }
530 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
531 mGnssNavigationMessageProvider.addListener(
532 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
533 callerIdentity.mUid, callerIdentity.mPackageName);
534 } else {
535 mGnssNavigationMessageProvider.removeListener(
536 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
537 }
538 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700539 }
540 }
541
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800542 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700543 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800544 }
545
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800546 private void onBackgroundThrottleIntervalChanged() {
547 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
548 for (LocationProvider provider : mProviders) {
549 applyRequirements(provider.getName());
Amith Yamasanib27528d2014-06-05 15:02:10 -0700550 }
551 }
552
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800553 private void onBackgroundThrottleWhitelistChanged() {
554 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
555 updateBackgroundThrottlingWhitelist();
556 for (LocationProvider provider : mProviders) {
557 applyRequirements(provider.getName());
Amith Yamasanib27528d2014-06-05 15:02:10 -0700558 }
559 }
560
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800561 private void updateUserProfiles(int currentUserId) {
562 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
563 mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(currentUserId);
564 }
565
566 private boolean isCurrentProfile(int userId) {
567 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
568 return ArrayUtils.contains(mCurrentUserProfiles, userId);
569 }
570
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700571 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800572 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500573 PackageManager pm = mContext.getPackageManager();
574 String systemPackageName = mContext.getPackageName();
575 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
576
577 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
578 new Intent(FUSED_LOCATION_SERVICE_ACTION),
579 PackageManager.GET_META_DATA, mCurrentUserId);
580 for (ResolveInfo rInfo : rInfos) {
581 String packageName = rInfo.serviceInfo.packageName;
582
583 // Check that the signature is in the list of supported sigs. If it's not in
584 // this list the standard provider binding logic won't bind to it.
585 try {
586 PackageInfo pInfo;
587 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
588 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
589 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
590 ", but has wrong signature, ignoring");
591 continue;
592 }
593 } catch (NameNotFoundException e) {
594 Log.e(TAG, "missing package: " + packageName);
595 continue;
596 }
597
598 // Get the version info
599 if (rInfo.serviceInfo.metaData == null) {
600 Log.w(TAG, "Found fused provider without metadata: " + packageName);
601 continue;
602 }
603
604 int version = rInfo.serviceInfo.metaData.getInt(
605 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
606 if (version == 0) {
607 // This should be the fallback fused location provider.
608
609 // Make sure it's in the system partition.
610 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
611 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
612 continue;
613 }
614
615 // Check that the fallback is signed the same as the OS
616 // as a proxy for coreApp="true"
617 if (pm.checkSignatures(systemPackageName, packageName)
618 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800619 if (D) {
620 Log.d(TAG, "Fallback candidate not signed the same as system: "
621 + packageName);
622 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500623 continue;
624 }
625
626 // Found a valid fallback.
627 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
628 return;
629 } else {
630 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
631 }
632 }
633
634 throw new IllegalStateException("Unable to find a fused location provider that is in the "
635 + "system partition with version 0 and signed with the platform certificate. "
636 + "Such a package is needed to provide a default fused location provider in the "
637 + "event that no other fused location provider has been installed or is currently "
638 + "available. For example, coreOnly boot mode when decrypting the data "
639 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
640 }
641
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700642 private void loadProvidersLocked() {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800643 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Victoria Lease5c24fd02012-10-01 11:00:50 -0700644 // create a passive location provider, which is always enabled
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700645 LocationProvider passiveProviderManager = new LocationProvider(
646 LocationManager.PASSIVE_PROVIDER);
647 PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager);
648
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800649 addProvider(passiveProviderManager);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700650 mPassiveProvider = passiveProvider;
651
Lifu Tang30f95a72016-01-07 23:20:38 -0800652 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700653 // Create a gps location provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700654 LocationProvider gnssProviderManager = new LocationProvider(
655 LocationManager.GPS_PROVIDER);
656 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
657 gnssProviderManager,
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800658 mHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700659
Lifu Tang9363b942016-02-16 18:07:00 -0800660 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800661 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700662 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800663 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
664 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800665 addProvider(gnssProviderManager);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700666 mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager);
Lifu Tang818aa2c2016-02-01 01:52:00 -0800667 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
668 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800669 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700670 }
671
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700672 /*
673 Load package name(s) containing location provider support.
674 These packages can contain services implementing location providers:
675 Geocoder Provider, Network Location Provider, and
676 Fused Location Provider. They will each be searched for
677 service components implementing these providers.
678 The location framework also has support for installation
679 of new location providers at run-time. The new package does not
680 have to be explicitly listed here, however it must have a signature
681 that matches the signature of at least one package on this list.
682 */
683 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500684 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700685 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800686 if (D) {
687 Log.d(TAG, "certificates for location providers pulled from: " +
688 Arrays.toString(pkgs));
689 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500690
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700691 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700692
693 // bind to network provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700694
695 LocationProvider networkProviderManager = new LocationProvider(
696 LocationManager.NETWORK_PROVIDER);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700697 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
698 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700699 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700700 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700701 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
702 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700703 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700704 if (networkProvider != null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700705 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700706 mProxyProviders.add(networkProvider);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800707 addProvider(networkProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700708 } else {
gomo48f1a642017-11-10 20:35:46 -0800709 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700710 }
711
712 // bind to fused provider
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700713 LocationProvider fusedProviderManager = new LocationProvider(
714 LocationManager.FUSED_PROVIDER);
715 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700716 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700717 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700718 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700719 com.android.internal.R.bool.config_enableFusedLocationOverlay,
720 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700721 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700722 if (fusedProvider != null) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800723 addProvider(fusedProviderManager);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700724 mProxyProviders.add(fusedProvider);
725 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700726 } else {
727 Slog.e(TAG, "no fused location provider found",
728 new IllegalStateException("Location service needs a fused location provider"));
729 }
730
731 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700732 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
733 com.android.internal.R.bool.config_enableGeocoderOverlay,
734 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700735 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700736 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800737 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700738 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700739
destradaaf9a274c2014-07-25 15:11:56 -0700740 // bind to geofence provider
741 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800742 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700743 com.android.internal.R.string.config_geofenceProviderPackageName,
744 com.android.internal.R.array.config_locationProviderPackageNames,
Wei Liu5241a4c2015-05-11 14:00:36 -0700745 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900746 null);
destradaaf9a274c2014-07-25 15:11:56 -0700747 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800748 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700749 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900750
destradaa6e2fe752015-06-23 17:25:53 -0700751 // bind to hardware activity recognition
752 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
753 ActivityRecognitionHardware activityRecognitionHardware = null;
754 if (activityRecognitionHardwareIsSupported) {
755 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700756 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700757 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700758 }
destradaa6e2fe752015-06-23 17:25:53 -0700759 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
760 mContext,
destradaa6e2fe752015-06-23 17:25:53 -0700761 activityRecognitionHardwareIsSupported,
762 activityRecognitionHardware,
763 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
764 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
765 com.android.internal.R.array.config_locationProviderPackageNames);
766 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700767 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700768 }
destradaaa4fa3b52014-07-09 10:46:39 -0700769
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900770 String[] testProviderStrings = resources.getStringArray(
771 com.android.internal.R.array.config_testLocationProviders);
772 for (String testProviderString : testProviderStrings) {
773 String fragments[] = testProviderString.split(",");
774 String name = fragments[0].trim();
775 if (mProvidersByName.get(name) != null) {
776 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
777 }
778 ProviderProperties properties = new ProviderProperties(
779 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
780 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
781 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
782 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
783 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
784 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
785 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
786 Integer.parseInt(fragments[8]) /* powerRequirement */,
787 Integer.parseInt(fragments[9]) /* accuracy */);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800788 addTestProvider(name, properties);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900789 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700790 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700791
Victoria Lease38389b62012-09-30 11:44:22 -0700792 private void switchUser(int userId) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800793 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800794 if (mCurrentUserId == userId) {
795 return;
796 }
Victoria Lease83762d22012-10-03 13:51:17 -0700797 mBlacklist.switchUser(userId);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800798 mHandler.removeMessages(MSG_LOCATION_CHANGED);
799 mLastLocation.clear();
800 mLastLocationCoarseInterval.clear();
801 updateUserProfiles(userId);
802 updateProvidersSettings();
803 mCurrentUserId = userId;
Victoria Lease38389b62012-09-30 11:44:22 -0700804 }
805
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800806 private static final class Identity {
807 final int mUid;
808 final int mPid;
809 final String mPackageName;
810
811 Identity(int uid, int pid, String packageName) {
812 mUid = uid;
813 mPid = pid;
814 mPackageName = packageName;
815 }
816 }
817
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700818 private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
819
820 private final String mName;
821 private AbstractLocationProvider mProvider;
822
823 // whether the provider is enabled in location settings
824 private boolean mSettingsEnabled;
825
826 // whether the provider considers itself enabled
827 private volatile boolean mEnabled;
828
829 @Nullable
830 private volatile ProviderProperties mProperties;
831
832 private LocationProvider(String name) {
833 mName = name;
834 // TODO: initialize settings enabled?
835 }
836
837 @Override
838 public void onAttachProvider(AbstractLocationProvider provider, boolean initiallyEnabled) {
839 checkState(mProvider == null);
840
841 // the provider is not yet fully constructed at this point, so we may not do anything
842 // except save a reference for later use here. do not call any provider methods.
843 mProvider = provider;
844 mEnabled = initiallyEnabled;
845 mProperties = null;
846 }
847
848 public String getName() {
849 return mName;
850 }
851
852 public boolean isEnabled() {
853 return mSettingsEnabled && mEnabled;
854 }
855
856 @Nullable
857 public ProviderProperties getProperties() {
858 return mProperties;
859 }
860
861 public void setRequest(ProviderRequest request, WorkSource workSource) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800862 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700863 mProvider.setRequest(request, workSource);
864 }
865
866 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800867 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
868
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700869 pw.println(mName + " provider:");
870 pw.println(" setting=" + mSettingsEnabled);
871 pw.println(" enabled=" + mEnabled);
872 pw.println(" properties=" + mProperties);
873 mProvider.dump(fd, pw, args);
874 }
875
876 public long getStatusUpdateTime() {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800877 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700878 return mProvider.getStatusUpdateTime();
879 }
880
881 public int getStatus(Bundle extras) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800882 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700883 return mProvider.getStatus(extras);
884 }
885
886 public void sendExtraCommand(String command, Bundle extras) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800887 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700888 mProvider.sendExtraCommand(command, extras);
889 }
890
891 // called from any thread
892 @Override
893 public void onReportLocation(Location location) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800894 // no security check necessary because this is coming from an internal-only interface
895 runInternal(() -> LocationManagerService.this.handleLocationChanged(location,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700896 mProvider == mPassiveProvider));
897 }
898
899 // called from any thread
900 @Override
901 public void onReportLocation(List<Location> locations) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800902 LocationManagerService.this.reportLocationBatch(locations);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700903 }
904
905 // called from any thread
906 @Override
907 public void onSetEnabled(boolean enabled) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800908 runInternal(() -> {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700909 if (enabled == mEnabled) {
910 return;
911 }
912
913 mEnabled = enabled;
914
915 if (!mSettingsEnabled) {
916 // this provider was disabled in settings anyways, so a change to it's own
917 // enabled status won't have any affect.
918 return;
919 }
920
921 // traditionally clients can listen for changes to the LOCATION_PROVIDERS_ALLOWED
922 // setting to detect when providers are enabled or disabled (even though they aren't
923 // supposed to). to continue to support this we must force a change to this setting.
924 // we use the fused provider because this is forced to be always enabled in settings
925 // anyways, and so won't have any visible effect beyond triggering content observers
926 Settings.Secure.putStringForUser(mContext.getContentResolver(),
927 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
928 "+" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
929 Settings.Secure.putStringForUser(mContext.getContentResolver(),
930 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
931 "-" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
932
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800933 if (!enabled) {
934 // If any provider has been disabled, clear all last locations for all
935 // providers. This is to be on the safe side in case a provider has location
936 // derived from this disabled provider.
937 mLastLocation.clear();
938 mLastLocationCoarseInterval.clear();
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700939 }
940
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800941 updateProviderListeners(mName);
942
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700943 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
944 UserHandle.ALL);
945 });
946 }
947
948 @Override
949 public void onSetProperties(ProviderProperties properties) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800950 runInternal(() -> {
951 mProperties = properties;
952 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700953 }
954
955 private void setSettingsEnabled(boolean enabled) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800956 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
957 if (mSettingsEnabled == enabled) {
958 return;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700959 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700960
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800961 mSettingsEnabled = enabled;
962 if (!mSettingsEnabled) {
963 // if any provider has been disabled, clear all last locations for all
964 // providers. this is to be on the safe side in case a provider has location
965 // derived from this disabled provider.
966 mLastLocation.clear();
967 mLastLocationCoarseInterval.clear();
968 updateProviderListeners(mName);
969 } else if (mEnabled) {
970 updateProviderListeners(mName);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700971 }
972 }
973 }
974
Victoria Lease38389b62012-09-30 11:44:22 -0700975 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
977 * location updates.
978 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700979 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -0700980 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800981 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700982 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700983
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700984 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -0700986 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700987 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
988 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700989
gomo48f1a642017-11-10 20:35:46 -0800990 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700991
David Christie0b837452013-07-29 16:02:13 -0700992 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700993 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -0700994 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700995 private boolean mOpHighPowerMonitoring;
996 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -0700997 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700999 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001000 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001003 if (listener != null) {
1004 mKey = listener.asBinder();
1005 } else {
1006 mKey = intent;
1007 }
Victoria Lease37425c32012-10-16 16:08:48 -07001008 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001009 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +00001010 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -07001011 workSource = null;
1012 }
1013 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -07001014 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -07001015
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001016 updateMonitoring(true);
1017
Victoria Lease0aa28602013-05-29 15:28:26 -07001018 // construct/configure wakelock
1019 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -07001020 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001021 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001022 }
1023 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -07001024
1025 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
1026 // only need to release it once.
1027 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 }
1029
1030 @Override
1031 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001032 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 }
1034
1035 @Override
1036 public int hashCode() {
1037 return mKey.hashCode();
1038 }
Mike Lockwood3681f262009-05-12 10:52:03 -04001039
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 @Override
1041 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001042 StringBuilder s = new StringBuilder();
1043 s.append("Reciever[");
1044 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001046 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001048 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001050 for (String p : mUpdateRecords.keySet()) {
1051 s.append(" ").append(mUpdateRecords.get(p).toString());
1052 }
Wei Wangdd070f22018-06-21 11:29:40 -07001053 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001054 s.append("]");
1055 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 }
1057
David Christie15b31912013-08-13 15:54:32 -07001058 /**
1059 * Update AppOp monitoring for this receiver.
1060 *
1061 * @param allow If true receiver is currently active, if false it's been removed.
1062 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001063 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001064 if (mHideFromAppOps) {
1065 return;
1066 }
1067
David Christie15b31912013-08-13 15:54:32 -07001068 boolean requestingLocation = false;
1069 boolean requestingHighPowerLocation = false;
1070 if (allow) {
1071 // See if receiver has any enabled update records. Also note if any update records
1072 // are high power (has a high power provider with an interval under a threshold).
1073 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001074 if (isAllowedByUserSettingsForUser(updateRecord.mProvider,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001075 mCurrentUserId)) {
David Christie15b31912013-08-13 15:54:32 -07001076 requestingLocation = true;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001077 LocationManagerService.LocationProvider locationProvider
David Christie2ff96af2014-01-30 16:09:37 -08001078 = mProvidersByName.get(updateRecord.mProvider);
David Christie15b31912013-08-13 15:54:32 -07001079 ProviderProperties properties = locationProvider != null
1080 ? locationProvider.getProperties() : null;
1081 if (properties != null
1082 && properties.mPowerRequirement == Criteria.POWER_HIGH
1083 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1084 requestingHighPowerLocation = true;
1085 break;
1086 }
1087 }
1088 }
1089 }
1090
David Christie0b837452013-07-29 16:02:13 -07001091 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001092 mOpMonitoring = updateMonitoring(
1093 requestingLocation,
1094 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001095 AppOpsManager.OP_MONITOR_LOCATION);
1096
1097 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001098 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001099 mOpHighPowerMonitoring = updateMonitoring(
1100 requestingHighPowerLocation,
1101 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001102 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001103 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001104 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001105 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1106 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1107 }
David Christie0b837452013-07-29 16:02:13 -07001108 }
1109
1110 /**
1111 * Update AppOps monitoring for a single location request and op type.
1112 *
gomo48f1a642017-11-10 20:35:46 -08001113 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001114 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001115 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001116 * @return True if monitoring is on for this request/op after updating.
1117 */
1118 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1119 int op) {
1120 if (!currentlyMonitoring) {
1121 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001122 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001123 == AppOpsManager.MODE_ALLOWED;
1124 }
1125 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001126 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001127 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001128 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001129 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001130 return false;
1131 }
1132 }
1133
1134 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001135 }
1136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 public boolean isListener() {
1138 return mListener != null;
1139 }
1140
1141 public boolean isPendingIntent() {
1142 return mPendingIntent != null;
1143 }
1144
1145 public ILocationListener getListener() {
1146 if (mListener != null) {
1147 return mListener;
1148 }
1149 throw new IllegalStateException("Request for non-existent listener");
1150 }
1151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1153 if (mListener != null) {
1154 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001155 synchronized (this) {
1156 // synchronize to ensure incrementPendingBroadcastsLocked()
1157 // is called before decrementPendingBroadcasts()
1158 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001159 // call this after broadcasting so we do not increment
1160 // if we throw an exeption.
1161 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 } catch (RemoteException e) {
1164 return false;
1165 }
1166 } else {
1167 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001168 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1170 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001171 synchronized (this) {
1172 // synchronize to ensure incrementPendingBroadcastsLocked()
1173 // is called before decrementPendingBroadcasts()
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001174 mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001175 getResolutionPermission(mAllowedResolutionLevel),
1176 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001177 // call this after broadcasting so we do not increment
1178 // if we throw an exeption.
1179 incrementPendingBroadcastsLocked();
1180 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 } catch (PendingIntent.CanceledException e) {
1182 return false;
1183 }
1184 }
1185 return true;
1186 }
1187
1188 public boolean callLocationChangedLocked(Location location) {
1189 if (mListener != null) {
1190 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001191 synchronized (this) {
1192 // synchronize to ensure incrementPendingBroadcastsLocked()
1193 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001194 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001195 // call this after broadcasting so we do not increment
1196 // if we throw an exeption.
1197 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 } catch (RemoteException e) {
1200 return false;
1201 }
1202 } else {
1203 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001204 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1205 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001207 synchronized (this) {
1208 // synchronize to ensure incrementPendingBroadcastsLocked()
1209 // is called before decrementPendingBroadcasts()
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001210 mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001211 getResolutionPermission(mAllowedResolutionLevel),
1212 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001213 // call this after broadcasting so we do not increment
1214 // if we throw an exeption.
1215 incrementPendingBroadcastsLocked();
1216 }
1217 } catch (PendingIntent.CanceledException e) {
1218 return false;
1219 }
1220 }
1221 return true;
1222 }
1223
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001224 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001225 // First update AppOp monitoring.
1226 // An app may get/lose location access as providers are enabled/disabled.
1227 updateMonitoring(true);
1228
Mike Lockwood48f17512009-04-23 09:12:08 -07001229 if (mListener != null) {
1230 try {
1231 synchronized (this) {
1232 // synchronize to ensure incrementPendingBroadcastsLocked()
1233 // is called before decrementPendingBroadcasts()
1234 if (enabled) {
1235 mListener.onProviderEnabled(provider);
1236 } else {
1237 mListener.onProviderDisabled(provider);
1238 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001239 // call this after broadcasting so we do not increment
1240 // if we throw an exeption.
1241 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001242 }
1243 } catch (RemoteException e) {
1244 return false;
1245 }
1246 } else {
1247 Intent providerIntent = new Intent();
1248 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1249 try {
1250 synchronized (this) {
1251 // synchronize to ensure incrementPendingBroadcastsLocked()
1252 // is called before decrementPendingBroadcasts()
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001253 mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001254 getResolutionPermission(mAllowedResolutionLevel),
1255 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001256 // call this after broadcasting so we do not increment
1257 // if we throw an exeption.
1258 incrementPendingBroadcastsLocked();
1259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 } catch (PendingIntent.CanceledException e) {
1261 return false;
1262 }
1263 }
1264 return true;
1265 }
1266
Nick Pellyf1be6862012-05-15 10:53:42 -07001267 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001269 if (D) Log.d(TAG, "Location listener died");
1270
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001271 runInternal(() -> {
1272 removeUpdates(this);
1273 synchronized (this) {
1274 clearPendingBroadcastsLocked();
1275 }
1276 });
Mike Lockwood48f17512009-04-23 09:12:08 -07001277 }
1278
Nick Pellye0fd6932012-07-11 10:26:13 -07001279 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001280 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1281 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001282 synchronized (this) {
1283 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001284 }
1285 }
1286
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001287 // this must be called while synchronized by caller in a synchronized block
1288 // containing the sending of the broadcaset
1289 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001290 mPendingBroadcasts++;
1291 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001292 }
1293
1294 private void decrementPendingBroadcastsLocked() {
1295 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001296 if (mWakeLock.isHeld()) {
1297 mWakeLock.release();
1298 }
1299 }
1300 }
1301
1302 public void clearPendingBroadcastsLocked() {
1303 if (mPendingBroadcasts > 0) {
1304 mPendingBroadcasts = 0;
1305 if (mWakeLock.isHeld()) {
1306 mWakeLock.release();
1307 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001308 }
1309 }
1310 }
1311
Nick Pellye0fd6932012-07-11 10:26:13 -07001312 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001313 public void locationCallbackFinished(ILocationListener listener) throws RemoteException {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001314 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001315 //the receiver list if it is not found. If it is not found then the
1316 //LocationListener was removed when it had a pending broadcast and should
1317 //not be added back.
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001318 runFromBinderBlocking(() -> {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001319 IBinder binder = listener.asBinder();
1320 Receiver receiver = mReceivers.get(binder);
1321 if (receiver != null) {
1322 synchronized (receiver) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001323 receiver.decrementPendingBroadcastsLocked();
David Christie2ff96af2014-01-30 16:09:37 -08001324 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001325 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001326 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 }
1328
Lifu Tang82f893d2016-01-21 18:15:33 -08001329 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001330 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001331 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001332 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001333 } else {
1334 return 0;
1335 }
1336 }
1337
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001338 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001339 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001340 public String getGnssHardwareModelName() {
1341 if (mGnssSystemInfoProvider != null) {
1342 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1343 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001344 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001345 }
1346 }
1347
Wyatt Rileycf879db2017-01-12 13:57:38 -08001348 private boolean hasGnssPermissions(String packageName) {
1349 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1350 checkResolutionLevelIsSufficientForProviderUse(
1351 allowedResolutionLevel,
1352 LocationManager.GPS_PROVIDER);
1353
1354 int pid = Binder.getCallingPid();
1355 int uid = Binder.getCallingUid();
1356 long identity = Binder.clearCallingIdentity();
1357 boolean hasLocationAccess;
1358 try {
1359 hasLocationAccess = checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1360 } finally {
1361 Binder.restoreCallingIdentity(identity);
1362 }
1363
1364 return hasLocationAccess;
1365 }
1366
Wyatt Rileycf879db2017-01-12 13:57:38 -08001367 @Override
1368 public int getGnssBatchSize(String packageName) {
1369 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1370 "Location Hardware permission not granted to access hardware batching");
1371
1372 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001373 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001374 } else {
1375 return 0;
1376 }
1377 }
1378
Wyatt Rileycf879db2017-01-12 13:57:38 -08001379 @Override
1380 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1381 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1382 "Location Hardware permission not granted to access hardware batching");
1383
1384 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1385 return false;
1386 }
1387
1388 mGnssBatchingCallback = callback;
1389 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1390 try {
1391 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1392 } catch (RemoteException e) {
1393 // if the remote process registering the listener is already dead, just swallow the
1394 // exception and return
1395 Log.e(TAG, "Remote listener already died.", e);
1396 return false;
1397 }
1398
1399 return true;
1400 }
1401
1402 private class LinkedCallback implements IBinder.DeathRecipient {
1403 private final IBatchedLocationCallback mCallback;
1404
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001405 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001406 mCallback = callback;
1407 }
1408
1409 @NonNull
1410 public IBatchedLocationCallback getUnderlyingListener() {
1411 return mCallback;
1412 }
1413
1414 @Override
1415 public void binderDied() {
1416 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1417 stopGnssBatch();
1418 removeGnssBatchingCallback();
1419 }
1420 }
1421
Wyatt Rileycf879db2017-01-12 13:57:38 -08001422 @Override
1423 public void removeGnssBatchingCallback() {
1424 try {
1425 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1426 0 /* flags */);
1427 } catch (NoSuchElementException e) {
1428 // if the death callback isn't connected (it should be...), log error, swallow the
1429 // exception and return
1430 Log.e(TAG, "Couldn't unlink death callback.", e);
1431 }
1432 mGnssBatchingCallback = null;
1433 mGnssBatchingDeathCallback = null;
1434 }
1435
Wyatt Rileycf879db2017-01-12 13:57:38 -08001436 @Override
1437 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1438 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1439 "Location Hardware permission not granted to access hardware batching");
1440
1441 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1442 return false;
1443 }
1444
1445 if (mGnssBatchingInProgress) {
1446 // Current design does not expect multiple starts to be called repeatedly
1447 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1448 // Try to clean up anyway, and continue
1449 stopGnssBatch();
1450 }
1451
1452 mGnssBatchingInProgress = true;
1453 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1454 }
1455
Wyatt Rileycf879db2017-01-12 13:57:38 -08001456 @Override
1457 public void flushGnssBatch(String packageName) {
1458 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1459 "Location Hardware permission not granted to access hardware batching");
1460
1461 if (!hasGnssPermissions(packageName)) {
1462 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1463 return;
1464 }
1465
1466 if (!mGnssBatchingInProgress) {
1467 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1468 }
1469
1470 if (mGnssBatchingProvider != null) {
gomo48f1a642017-11-10 20:35:46 -08001471 mGnssBatchingProvider.flush();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001472 }
1473 }
1474
Wyatt Rileycf879db2017-01-12 13:57:38 -08001475 @Override
1476 public boolean stopGnssBatch() {
1477 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1478 "Location Hardware permission not granted to access hardware batching");
1479
1480 if (mGnssBatchingProvider != null) {
1481 mGnssBatchingInProgress = false;
1482 return mGnssBatchingProvider.stop();
gomo48f1a642017-11-10 20:35:46 -08001483 } else {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001484 return false;
1485 }
1486 }
1487
1488 @Override
1489 public void reportLocationBatch(List<Location> locations) {
1490 checkCallerIsProvider();
1491
1492 // Currently used only for GNSS locations - update permissions check if changed
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001493 if (isAllowedByUserSettingsForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001494 if (mGnssBatchingCallback == null) {
1495 Slog.e(TAG, "reportLocationBatch() called without active Callback");
1496 return;
1497 }
1498 try {
1499 mGnssBatchingCallback.onLocationBatch(locations);
1500 } catch (RemoteException e) {
1501 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1502 }
1503 } else {
1504 Slog.w(TAG, "reportLocationBatch() called without user permission, locations blocked");
1505 }
1506 }
1507
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001508 private void addProvider(LocationProvider provider) {
1509 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001510 mProviders.add(provider);
1511 mProvidersByName.put(provider.getName(), provider);
1512 }
1513
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001514 private void removeProvider(LocationProvider provider) {
1515 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001516 mProviders.remove(provider);
1517 mProvidersByName.remove(provider.getName());
1518 }
1519
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001520 private boolean isAllowedByUserSettingsForUser(String provider, int userId) {
1521 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001522 if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001523 return isLocationEnabledForUserInternal(userId);
Maggie2a9409e2018-03-21 11:47:28 -07001524 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001525 if (LocationManager.FUSED_PROVIDER.equals(provider)) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001526 return isLocationEnabledForUserInternal(userId);
Maggie2a9409e2018-03-21 11:47:28 -07001527 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001528 if (mMockProviders.containsKey(provider)) {
1529 return isLocationEnabledForUserInternal(userId);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001530 }
1531
1532 long identity = Binder.clearCallingIdentity();
1533 try {
1534 // Use system settings
1535 ContentResolver cr = mContext.getContentResolver();
1536 String allowedProviders = Settings.Secure.getStringForUser(
1537 cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
1538 return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
1539 } finally {
1540 Binder.restoreCallingIdentity(identity);
1541 }
Maggie2a9409e2018-03-21 11:47:28 -07001542 }
1543
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001544 private boolean isAllowedByUserSettings(String provider, int uid, int userId) {
1545 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Amith Yamasanib27528d2014-06-05 15:02:10 -07001546 if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
Victoria Lease09eeaec2013-02-05 11:34:13 -08001547 return false;
1548 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001549 return isAllowedByUserSettingsForUser(provider, userId);
Victoria Lease09eeaec2013-02-05 11:34:13 -08001550 }
1551
Victoria Lease37425c32012-10-16 16:08:48 -07001552 private String getResolutionPermission(int resolutionLevel) {
1553 switch (resolutionLevel) {
1554 case RESOLUTION_LEVEL_FINE:
1555 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1556 case RESOLUTION_LEVEL_COARSE:
1557 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1558 default:
1559 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001561 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001562
Victoria Lease37425c32012-10-16 16:08:48 -07001563 private int getAllowedResolutionLevel(int pid, int uid) {
1564 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001565 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001566 return RESOLUTION_LEVEL_FINE;
1567 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001568 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001569 return RESOLUTION_LEVEL_COARSE;
1570 } else {
1571 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001572 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001573 }
1574
Victoria Lease37425c32012-10-16 16:08:48 -07001575 private int getCallerAllowedResolutionLevel() {
1576 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1577 }
1578
Victoria Lease37425c32012-10-16 16:08:48 -07001579 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1580 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001581 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 }
1584
Victoria Lease37425c32012-10-16 16:08:48 -07001585 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001586 if (LocationManager.GPS_PROVIDER.equals(provider) ||
1587 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
1588 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001589 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -07001590 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
1591 LocationManager.FUSED_PROVIDER.equals(provider)) {
1592 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001593 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001594 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001595 for (LocationProvider lp : mProviders) {
1596 if (!lp.getName().equals(provider)) {
1597 continue;
1598 }
1599
Laurent Tu941221c2012-10-04 14:21:52 -07001600 ProviderProperties properties = lp.getProperties();
1601 if (properties != null) {
1602 if (properties.mRequiresSatellite) {
1603 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001604 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001605 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1606 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001607 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001608 }
1609 }
1610 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001611 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001612
Victoria Lease37425c32012-10-16 16:08:48 -07001613 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001614 }
1615
Victoria Lease37425c32012-10-16 16:08:48 -07001616 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
1617 String providerName) {
1618 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
1619 if (allowedResolutionLevel < requiredResolutionLevel) {
1620 switch (requiredResolutionLevel) {
1621 case RESOLUTION_LEVEL_FINE:
1622 throw new SecurityException("\"" + providerName + "\" location provider " +
1623 "requires ACCESS_FINE_LOCATION permission.");
1624 case RESOLUTION_LEVEL_COARSE:
1625 throw new SecurityException("\"" + providerName + "\" location provider " +
1626 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1627 default:
1628 throw new SecurityException("Insufficient permission for \"" + providerName +
1629 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001630 }
1631 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001632 }
1633
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001634 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001635 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1636 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001637 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001638 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001639 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001640 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001641 }
1642 return -1;
1643 }
1644
Wei Wangb86334f2018-07-03 16:33:24 -07001645 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001646 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001647 case RESOLUTION_LEVEL_COARSE:
1648 return AppOpsManager.OPSTR_COARSE_LOCATION;
1649 case RESOLUTION_LEVEL_FINE:
1650 return AppOpsManager.OPSTR_FINE_LOCATION;
1651 case RESOLUTION_LEVEL_NONE:
1652 // The client is not allowed to get any location, so both FINE and COARSE ops will
1653 // be denied. Pick the most restrictive one to be safe.
1654 return AppOpsManager.OPSTR_FINE_LOCATION;
1655 default:
1656 // Use the most restrictive ops if not sure.
1657 return AppOpsManager.OPSTR_FINE_LOCATION;
1658 }
1659 }
1660
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001661 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001662 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001663 int op = resolutionLevelToOp(allowedResolutionLevel);
1664 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001665 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1666 return false;
1667 }
1668 }
David Christieb870dbf2015-06-22 12:42:53 -07001669
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001670 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001671 }
1672
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001673 private boolean checkLocationAccess(int pid, int uid, String packageName,
1674 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001675 int op = resolutionLevelToOp(allowedResolutionLevel);
1676 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001677 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001678 return false;
1679 }
1680 }
David Christieb870dbf2015-06-22 12:42:53 -07001681
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001682 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001683 }
1684
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001685 /**
Maggie91e630c2018-01-24 17:31:46 -08001686 * Returns all providers by name, including passive and the ones that are not permitted to
1687 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001688 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001689 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 public List<String> getAllProviders() {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001691 ArrayList<String> providers = new ArrayList<>(mProviders.size());
1692 for (LocationProvider provider : mProviders) {
1693 String name = provider.getName();
1694 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1695 continue;
Maggie91e630c2018-01-24 17:31:46 -08001696 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001697 providers.add(name);
Maggie91e630c2018-01-24 17:31:46 -08001698 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001699 return providers;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 }
1701
Mike Lockwood03ca2162010-04-01 08:10:09 -07001702 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001703 * Return all providers by name, that match criteria and are optionally
1704 * enabled.
1705 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001706 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001707 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001708 public List<String> getProviders(Criteria criteria, boolean enabledOnly)
1709 throws RemoteException {
Victoria Lease37425c32012-10-16 16:08:48 -07001710 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001711 int uid = Binder.getCallingUid();
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001712 return runFromBinderBlocking(() -> {
1713 ArrayList<String> providers = new ArrayList<>(mProviders.size());
1714 for (LocationProvider provider : mProviders) {
1715 String name = provider.getName();
1716 if (LocationManager.FUSED_PROVIDER.equals(name)) {
1717 continue;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001718 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001719 if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUse(name)) {
1720 continue;
1721 }
1722 if (enabledOnly
1723 && !isAllowedByUserSettings(name, uid, mCurrentUserId)) {
1724 continue;
1725 }
1726 if (criteria != null
1727 && !android.location.LocationProvider.propertiesMeetCriteria(
1728 name, provider.getProperties(), criteria)) {
1729 continue;
1730 }
1731 providers.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001732 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001733 return providers;
1734 });
Mike Lockwood03ca2162010-04-01 08:10:09 -07001735 }
1736
1737 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001738 * Return the name of the best provider given a Criteria object.
1739 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001740 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001741 * has been deprecated as well. So this method now uses
1742 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001743 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001744 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001745 public String getBestProvider(Criteria criteria, boolean enabledOnly) throws RemoteException {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001746 List<String> providers = getProviders(criteria, enabledOnly);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001747 if (providers.isEmpty()) {
1748 providers = getProviders(null, enabledOnly);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001749 }
1750
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001751 if (!providers.isEmpty()) {
1752 if (providers.contains(LocationManager.GPS_PROVIDER)) {
1753 return LocationManager.GPS_PROVIDER;
1754 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
1755 return LocationManager.NETWORK_PROVIDER;
1756 } else {
1757 return providers.get(0);
1758 }
1759 }
1760
Mike Lockwood03ca2162010-04-01 08:10:09 -07001761 return null;
1762 }
1763
Nick Pellye0fd6932012-07-11 10:26:13 -07001764 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001765 public boolean providerMeetsCriteria(String provider, Criteria criteria)
1766 throws RemoteException {
1767 return runFromBinderBlocking(() -> {
1768 LocationProvider p = mProvidersByName.get(provider);
1769 if (p == null) {
1770 throw new IllegalArgumentException("provider=" + provider);
1771 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001772
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001773 return android.location.LocationProvider.propertiesMeetCriteria(
1774 p.getName(), p.getProperties(), criteria);
1775 });
Mike Lockwood03ca2162010-04-01 08:10:09 -07001776 }
1777
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001778 private void updateProvidersSettings() {
1779 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001780 for (LocationProvider p : mProviders) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001781 p.setSettingsEnabled(isAllowedByUserSettingsForUser(p.getName(), mCurrentUserId));
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -07001782 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001783
1784 mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
1785 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 }
1787
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001788 private void updateProviderListeners(String provider) {
1789 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001790 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001791 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001793 boolean enabled = p.isEnabled();
1794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001796
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1798 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001799 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001800 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001801 // Sends a notification message to the receiver
1802 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
1803 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001804 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001805 }
1806 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809 }
1810 }
1811
1812 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001813 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001814 removeUpdates(deadReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 }
1816 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001817
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001818 applyRequirements(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 }
1820
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001821 private void applyRequirements(String provider) {
1822 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001823 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001824 if (p == null) return;
1825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001827 WorkSource worksource = new WorkSource();
1828 ProviderRequest providerRequest = new ProviderRequest();
1829
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001830 ContentResolver resolver = mContext.getContentResolver();
1831 long backgroundThrottleInterval = Settings.Global.getLong(
1832 resolver,
1833 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
1834 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
1835
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001836 if (p.isEnabled() && records != null && !records.isEmpty()) {
1837 // initialize the low power mode to true and set to false if any of the records requires
1838 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001839 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001840 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07001841 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001842 record.mReceiver.mIdentity.mPid,
1843 record.mReceiver.mIdentity.mUid,
1844 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001845 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001846 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001847 long interval = locationRequest.getInterval();
1848
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001849 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001850 if (!record.mIsForegroundUid) {
1851 interval = Math.max(interval, backgroundThrottleInterval);
1852 }
1853 if (interval != locationRequest.getInterval()) {
1854 locationRequest = new LocationRequest(locationRequest);
1855 locationRequest.setInterval(interval);
1856 }
1857 }
1858
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001859 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001860 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08001861 if (!locationRequest.isLowPowerMode()) {
1862 providerRequest.lowPowerMode = false;
1863 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001864 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001865 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001866 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001867 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001868 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001869 }
1870 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001871
1872 if (providerRequest.reportLocation) {
1873 // calculate who to blame for power
1874 // This is somewhat arbitrary. We pick a threshold interval
1875 // that is slightly higher that the minimum interval, and
1876 // spread the blame across all applications with a request
1877 // under that threshold.
1878 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
1879 for (UpdateRecord record : records) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001880 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001881 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07001882
1883 // Don't assign battery blame for update records whose
1884 // client has no permission to receive location data.
1885 if (!providerRequest.locationRequests.contains(locationRequest)) {
1886 continue;
1887 }
1888
Victoria Leaseb711d572012-10-02 13:14:11 -07001889 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07001890 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00001891 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07001892 worksource.add(record.mReceiver.mWorkSource);
1893 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00001894 // Assign blame to caller if there's no WorkSource associated with
1895 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07001896 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001897 record.mReceiver.mIdentity.mUid,
1898 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001899 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001900 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001901 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001903 }
1904 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001905
1906 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
1907 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 }
1909
Narayan Kamath32684dd2018-01-08 17:32:51 +00001910 /**
1911 * Whether a given {@code WorkSource} associated with a Location request is valid.
1912 */
1913 private static boolean isValidWorkSource(WorkSource workSource) {
1914 if (workSource.size() > 0) {
1915 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
1916 // by tags.
1917 return workSource.getName(0) != null;
1918 } else {
1919 // For now, make sure callers have supplied an attribution tag for use with
1920 // AppOpsManager. This might be relaxed in the future.
1921 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
1922 return workChains != null && !workChains.isEmpty() &&
1923 workChains.get(0).getAttributionTag() != null;
1924 }
1925 }
1926
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001927 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001928 public String[] getBackgroundThrottlingWhitelist() throws RemoteException {
1929 return runFromBinderBlocking(
1930 () -> mBackgroundThrottlePackageWhitelist.toArray(new String[0]));
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001931 }
1932
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001933 private void updateBackgroundThrottlingWhitelist() {
1934 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001935 String setting = Settings.Global.getString(
gomo48f1a642017-11-10 20:35:46 -08001936 mContext.getContentResolver(),
1937 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001938 if (setting == null) {
1939 setting = "";
1940 }
1941
1942 mBackgroundThrottlePackageWhitelist.clear();
1943 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08001944 SystemConfig.getInstance().getAllowUnthrottledLocation());
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001945 mBackgroundThrottlePackageWhitelist.addAll(
gomo48f1a642017-11-10 20:35:46 -08001946 Arrays.asList(setting.split(",")));
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08001947 }
1948
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001949 private boolean isThrottlingExemptLocked(Identity identity) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001950 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001951 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001952 return true;
1953 }
1954
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001955 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001956 return true;
1957 }
1958
1959 for (LocationProviderProxy provider : mProxyProviders) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001960 if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001961 return true;
1962 }
1963 }
1964
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08001965 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001966 }
1967
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 private class UpdateRecord {
1969 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001970 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001971 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001972 private final Receiver mReceiver;
1973 private boolean mIsForegroundUid;
1974 private Location mLastFixBroadcast;
1975 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976
1977 /**
1978 * Note: must be constructed with lock held.
1979 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001980 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07001982 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001983 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001985 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001986 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987
1988 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1989 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001990 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 mRecordsByProvider.put(provider, records);
1992 }
1993 if (!records.contains(this)) {
1994 records.add(this);
1995 }
David Christie2ff96af2014-01-30 16:09:37 -08001996
1997 // Update statistics for historical location requests by package/provider
1998 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07001999 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2000 mIsForegroundUid);
2001 }
2002
2003 /**
2004 * Method to be called when record changes foreground/background
2005 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002006 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002007 mIsForegroundUid = isForeground;
2008 mRequestStatistics.updateForeground(
2009 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002010 }
2011
2012 /**
David Christie2ff96af2014-01-30 16:09:37 -08002013 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002014 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002015 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002016 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002017
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002018 // remove from mRecordsByProvider
2019 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2020 if (globalRecords != null) {
2021 globalRecords.remove(this);
2022 }
2023
2024 if (!removeReceiver) return; // the caller will handle the rest
2025
2026 // remove from Receiver#mUpdateRecords
2027 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002028 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002029
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002030 // and also remove the Receiver if it has no more update records
2031 if (receiverRecords.size() == 0) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002032 removeUpdates(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002033 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002034 }
2035
2036 @Override
2037 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002038 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002039 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2040 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002041 + ")" + " " + mRealRequest + " "
2042 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 }
2045
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002046 private Receiver getReceiver(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002047 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002048 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002049 IBinder binder = listener.asBinder();
2050 Receiver receiver = mReceivers.get(binder);
2051 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002052 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2053 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002054 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002055 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002056 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002057 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002058 return null;
2059 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002060 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002061 }
2062 return receiver;
2063 }
2064
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002065 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002066 WorkSource workSource, boolean hideFromAppOps) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002067 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002068 Receiver receiver = mReceivers.get(intent);
2069 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002070 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2071 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002072 mReceivers.put(intent, receiver);
2073 }
2074 return receiver;
2075 }
2076
Victoria Lease37425c32012-10-16 16:08:48 -07002077 /**
2078 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2079 * and consistency requirements.
2080 *
2081 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002082 * @return a version of request that meets the given resolution and consistency requirements
2083 * @hide
2084 */
gomo48f1a642017-11-10 20:35:46 -08002085 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2086 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002087 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002088 if (!callerHasLocationHardwarePermission) {
2089 // allow setting low power mode only for callers with location hardware permission
2090 sanitizedRequest.setLowPowerMode(false);
2091 }
Victoria Lease37425c32012-10-16 16:08:48 -07002092 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2093 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002094 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002095 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002096 break;
2097 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002098 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002099 break;
2100 }
2101 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002102 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2103 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002104 }
Victoria Lease37425c32012-10-16 16:08:48 -07002105 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2106 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002107 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002108 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002109 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002110 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002111 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002112 }
Victoria Lease37425c32012-10-16 16:08:48 -07002113 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002114 }
2115
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002116 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002117 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002118 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002119 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002120 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002121 String[] packages = mPackageManager.getPackagesForUid(uid);
2122 if (packages == null) {
2123 throw new SecurityException("invalid UID " + uid);
2124 }
2125 for (String pkg : packages) {
2126 if (packageName.equals(pkg)) return;
2127 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002128 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002129 }
2130
Nick Pellye0fd6932012-07-11 10:26:13 -07002131 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002132 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002133 PendingIntent intent, String packageName) throws RemoteException {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002134 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2135 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002136 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2137 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2138 request.getProvider());
David Christie82edc9b2013-07-19 11:31:42 -07002139 WorkSource workSource = request.getWorkSource();
Narayan Kamath32684dd2018-01-08 17:32:51 +00002140 if (workSource != null && !workSource.isEmpty()) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002141 mContext.enforceCallingOrSelfPermission(
2142 Manifest.permission.UPDATE_DEVICE_STATS, null);
David Christie40e57822013-07-30 11:36:48 -07002143 }
2144 boolean hideFromAppOps = request.getHideFromAppOps();
2145 if (hideFromAppOps) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002146 mContext.enforceCallingOrSelfPermission(
2147 Manifest.permission.UPDATE_APP_OPS_STATS, null);
David Christie82edc9b2013-07-19 11:31:42 -07002148 }
gomo48f1a642017-11-10 20:35:46 -08002149 boolean callerHasLocationHardwarePermission =
2150 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002151 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002152 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2153 callerHasLocationHardwarePermission);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002154
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002155 final int pid = Binder.getCallingPid();
2156 final int uid = Binder.getCallingUid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002157
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002158 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2159 // a location.
2160 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
2161
2162 if (intent == null && listener == null) {
2163 throw new IllegalArgumentException("need either listener or intent");
2164 } else if (intent != null && listener != null) {
2165 throw new IllegalArgumentException("cannot register both listener and intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002166 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002167
2168 runFromBinderBlocking(() -> {
2169 Receiver receiver;
2170 if (intent != null) {
2171 receiver = getReceiver(intent, pid, uid, packageName, workSource,
2172 hideFromAppOps);
2173 } else {
2174 receiver = getReceiver(listener, pid, uid, packageName, workSource,
2175 hideFromAppOps);
2176 }
2177 requestLocationUpdates(sanitizedRequest, receiver, uid, packageName);
2178 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 }
2180
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002181 private void requestLocationUpdates(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002182 int uid, String packageName) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002183 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002184 // Figure out the provider. Either its explicitly request (legacy use cases), or
2185 // use the fused provider
2186 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2187 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002188 if (name == null) {
2189 throw new IllegalArgumentException("provider name must not be null");
2190 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002191
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002192 LocationProvider provider = mProvidersByName.get(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002193 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002194 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002195 }
2196
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002197 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002198 if (D) {
2199 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2200 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2201 + (record.mIsForegroundUid ? "foreground" : "background")
2202 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002203 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002204 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002205
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002206 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2207 if (oldRecord != null) {
2208 oldRecord.disposeLocked(false);
2209 }
2210
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002211 if (provider.isEnabled()) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002212 applyRequirements(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002213 } else {
2214 // Notify the listener that updates are currently disabled
2215 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 }
David Christie0b837452013-07-29 16:02:13 -07002217 // Update the monitoring here just in case multiple location requests were added to the
2218 // same receiver (this request may be high power and the initial might not have been).
2219 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002220 }
2221
Nick Pellye0fd6932012-07-11 10:26:13 -07002222 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002223 public void removeUpdates(ILocationListener listener, PendingIntent intent,
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002224 String packageName) throws RemoteException {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002225 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002226
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002227 int pid = Binder.getCallingPid();
2228 int uid = Binder.getCallingUid();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002229
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002230 if (intent == null && listener == null) {
2231 throw new IllegalArgumentException("need either listener or intent");
2232 } else if (intent != null && listener != null) {
2233 throw new IllegalArgumentException("cannot register both listener and intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002234 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002235
2236 runFromBinderBlocking(() -> {
2237 Receiver receiver;
2238 if (intent != null) {
2239 receiver = getReceiver(intent, pid, uid, packageName, null, false);
2240 } else {
2241 receiver = getReceiver(listener, pid, uid, packageName, null, false);
2242 }
2243 removeUpdates(receiver);
2244 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002245 }
2246
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002247 private void removeUpdates(Receiver receiver) {
2248 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002249 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002250
2251 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2252 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2253 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002254 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002256 }
2257
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002258 receiver.updateMonitoring(false);
2259
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002260 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002261 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002262 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2263 if (oldRecords != null) {
2264 // Call dispose() on the obsolete update records.
2265 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002266 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002267 record.disposeLocked(false);
2268 }
2269 // Accumulate providers
2270 providers.addAll(oldRecords.keySet());
2271 }
2272
2273 // update provider
2274 for (String provider : providers) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002275 applyRequirements(provider);
Dianne Hackbornc2293022013-02-06 23:14:49 -08002276 }
2277 }
2278
Nick Pellye0fd6932012-07-11 10:26:13 -07002279 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002280 public Location getLastLocation(LocationRequest r, String packageName) throws RemoteException {
2281 if (D) Log.d(TAG, "getLastLocation: " + r);
2282 LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002283 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07002284 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002285 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2286 request.getProvider());
2287 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002288
David Christieb870dbf2015-06-22 12:42:53 -07002289 final int pid = Binder.getCallingPid();
Dianne Hackborna06de0f2012-12-11 16:34:47 -08002290 final int uid = Binder.getCallingUid();
2291 final long identity = Binder.clearCallingIdentity();
Victoria Leaseb711d572012-10-02 13:14:11 -07002292 try {
2293 if (mBlacklist.isBlacklisted(packageName)) {
gomo48f1a642017-11-10 20:35:46 -08002294 if (D) {
2295 Log.d(TAG, "not returning last loc for blacklisted app: " +
2296 packageName);
2297 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002298 return null;
2299 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002300
David Christieb870dbf2015-06-22 12:42:53 -07002301 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002302 if (D) {
2303 Log.d(TAG, "not returning last loc for no op app: " +
2304 packageName);
2305 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002306 return null;
2307 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002308 } finally {
2309 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002310 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002311
2312 return runFromBinderBlocking(() -> {
2313 // Figure out the provider. Either its explicitly request (deprecated API's),
2314 // or use the fused provider
2315 String name = request.getProvider();
2316 if (name == null) name = LocationManager.FUSED_PROVIDER;
2317 LocationProvider provider = mProvidersByName.get(name);
2318 if (provider == null) return null;
2319
2320 if (!isAllowedByUserSettings(name, uid, mCurrentUserId)) return null;
2321
2322 Location location;
2323 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2324 // Make sure that an app with coarse permissions can't get frequent location
2325 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2326 location = mLastLocationCoarseInterval.get(name);
2327 } else {
2328 location = mLastLocation.get(name);
2329 }
2330 if (location == null) {
2331 return null;
2332 }
2333
2334 // Don't return stale location to apps with foreground-only location permission.
2335 String op = resolutionLevelToOpStr(allowedResolutionLevel);
2336 long locationAgeMs = SystemClock.elapsedRealtime()
2337 - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2338 if ((locationAgeMs > Settings.Global.getLong(
2339 mContext.getContentResolver(),
2340 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2341 DEFAULT_LAST_LOCATION_MAX_AGE_MS))
2342 && (mAppOps.unsafeCheckOp(op, uid, packageName)
2343 == AppOpsManager.MODE_FOREGROUND)) {
2344 return null;
2345 }
2346
2347 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2348 Location noGPSLocation = location.getExtraLocation(
2349 Location.EXTRA_NO_GPS_LOCATION);
2350 if (noGPSLocation != null) {
2351 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
2352 }
2353 } else {
2354 return new Location(location);
2355 }
2356 return null;
2357 });
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002358 }
2359
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002360 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002361 public boolean injectLocation(Location location) throws RemoteException {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002362 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2363 "Location Hardware permission not granted to inject location");
2364 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2365 "Access Fine Location permission not granted to inject Location");
2366
2367 if (location == null) {
2368 if (D) {
2369 Log.d(TAG, "injectLocation(): called with null location");
2370 }
2371 return false;
2372 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002373
2374 return runFromBinderBlocking(() -> {
2375 LocationProvider p = null;
2376 String provider = location.getProvider();
2377 if (provider != null) {
2378 p = mProvidersByName.get(provider);
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002379 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002380 if (p == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002381 if (D) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002382 Log.d(TAG, "injectLocation(): unknown provider");
2383 }
2384 return false;
2385 }
2386 if (!isAllowedByUserSettingsForUser(provider, mCurrentUserId)) {
2387 if (D) {
2388 Log.d(TAG, "Location disabled in Settings for current user:"
2389 + mCurrentUserId);
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002390 }
2391 return false;
2392 } else {
2393 // NOTE: If last location is already available, location is not injected. If
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002394 // provider's normal source (like a GPS chipset) have already provided an output
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002395 // there is no need to inject this location.
2396 if (mLastLocation.get(provider) == null) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002397 updateLastLocation(location, provider);
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002398 } else {
2399 if (D) {
2400 Log.d(TAG, "injectLocation(): Location exists. Not updating");
2401 }
2402 return false;
2403 }
2404 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002405 return true;
2406 });
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002407 }
2408
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002409 @Override
2410 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2411 String packageName) {
2412 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002413 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2414 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002415 if (intent == null) {
2416 throw new IllegalArgumentException("invalid pending intent: " + null);
2417 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002418 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002419 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
2420 request.getProvider());
gomo48f1a642017-11-10 20:35:46 -08002421 // Require that caller can manage given document
2422 boolean callerHasLocationHardwarePermission =
2423 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
Maggieaa080f92018-01-04 15:35:11 -08002424 == PERMISSION_GRANTED;
gomo48f1a642017-11-10 20:35:46 -08002425 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel,
2426 callerHasLocationHardwarePermission);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002427
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002428 if (D) {
2429 Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " "
2430 + intent);
2431 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002432
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002433 // geo-fence manager uses the public location API, need to clear identity
2434 int uid = Binder.getCallingUid();
Xiaohui Chena4490622015-09-22 15:29:31 -07002435 // TODO: http://b/23822629
2436 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
Victoria Lease56e675b2012-11-05 19:25:06 -08002437 // temporary measure until geofences work for secondary users
2438 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2439 return;
2440 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002441 long identity = Binder.clearCallingIdentity();
2442 try {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002443 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
2444 uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002445 } finally {
2446 Binder.restoreCallingIdentity(identity);
2447 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002448 }
2449
2450 @Override
2451 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002452 if (intent == null) {
2453 throw new IllegalArgumentException("invalid pending intent: " + null);
2454 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002455 checkPackageName(packageName);
2456
2457 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2458
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002459 // geo-fence manager uses the public location API, need to clear identity
2460 long identity = Binder.clearCallingIdentity();
2461 try {
2462 mGeofenceManager.removeFence(geofence, intent);
2463 } finally {
2464 Binder.restoreCallingIdentity(identity);
2465 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002466 }
2467
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002468 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002469 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002470 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002471 return false;
2472 }
2473
Anil Admal75b9fd62018-11-28 11:22:50 -08002474 // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
2475 // measurements listeners.
2476 return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002477 }
2478
Nick Pellye0fd6932012-07-11 10:26:13 -07002479 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002480 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002481 mGnssStatusProvider.removeListener(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002482 }
2483
Nick Pellye0fd6932012-07-11 10:26:13 -07002484 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002485 public boolean addGnssMeasurementsListener(
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002486 IGnssMeasurementsListener listener, String packageName) throws RemoteException {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002487 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002488 return false;
2489 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002490
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002491 Identity callerIdentity =
2492 new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
2493 return runFromBinderBlocking(() -> {
Anil Admal75b9fd62018-11-28 11:22:50 -08002494 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002495 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002496 long identity = Binder.clearCallingIdentity();
2497 try {
2498 if (isThrottlingExemptLocked(callerIdentity)
2499 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002500 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002501 return mGnssMeasurementsProvider.addListener(listener,
2502 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002503 }
2504 } finally {
2505 Binder.restoreCallingIdentity(identity);
2506 }
2507
2508 return true;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002509 });
destradaaea8a8a62014-06-23 18:19:03 -07002510 }
2511
2512 @Override
gomo226b7b72018-12-12 16:49:39 -08002513 public void injectGnssMeasurementCorrections(
2514 GnssMeasurementCorrections measurementCorrections, String packageName) {
2515 mContext.enforceCallingPermission(
2516 android.Manifest.permission.LOCATION_HARDWARE,
2517 "Location Hardware permission not granted to inject GNSS measurement corrections.");
2518 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2519 mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
2520 } else {
2521 Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
2522 }
2523 }
2524
2525 @Override
2526 public int getGnssCapabilities(String packageName) {
2527 mContext.enforceCallingPermission(
2528 android.Manifest.permission.LOCATION_HARDWARE,
2529 "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
2530 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2531 return -1;
2532 }
2533 return mGnssMeasurementsProvider.getGnssCapabilities();
2534 }
2535
2536 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002537 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener)
2538 throws RemoteException {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002539 if (mGnssMeasurementsProvider == null) {
2540 return;
2541 }
2542
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002543 runFromBinderBlocking(() -> {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002544 mGnssMeasurementsListeners.remove(listener.asBinder());
2545 mGnssMeasurementsProvider.removeListener(listener);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002546 });
destradaaea8a8a62014-06-23 18:19:03 -07002547 }
2548
2549 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002550 public boolean addGnssNavigationMessageListener(
2551 IGnssNavigationMessageListener listener,
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002552 String packageName) throws RemoteException {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002553 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002554 return false;
2555 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002556
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002557 Identity callerIdentity =
2558 new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
2559
2560 return runFromBinderBlocking(() -> {
Anil Admal75b9fd62018-11-28 11:22:50 -08002561 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002562 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002563 long identity = Binder.clearCallingIdentity();
2564 try {
2565 if (isThrottlingExemptLocked(callerIdentity)
2566 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002567 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002568 return mGnssNavigationMessageProvider.addListener(listener,
2569 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002570 }
2571 } finally {
2572 Binder.restoreCallingIdentity(identity);
2573 }
2574
2575 return true;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002576 });
destradaa4b3e3932014-07-21 18:01:47 -07002577 }
2578
2579 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002580 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener)
2581 throws RemoteException {
Lifu Tang818aa2c2016-02-01 01:52:00 -08002582 if (mGnssNavigationMessageProvider != null) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002583 runFromBinderBlocking(() -> {
Wyatt Riley11cc7492018-01-17 08:48:27 -08002584 mGnssNavigationMessageListeners.remove(listener.asBinder());
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002585 mGnssNavigationMessageProvider.removeListener(listener);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002586 });
Wei Liu5241a4c2015-05-11 14:00:36 -07002587 }
destradaa4b3e3932014-07-21 18:01:47 -07002588 }
2589
2590 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002591 public boolean sendExtraCommand(String provider, String command, Bundle extras)
2592 throws RemoteException {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002593 if (provider == null) {
2594 // throw NullPointerException to remain compatible with previous implementation
2595 throw new NullPointerException();
2596 }
Victoria Lease37425c32012-10-16 16:08:48 -07002597 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2598 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002600 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04002601 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
Maggieaa080f92018-01-04 15:35:11 -08002602 != PERMISSION_GRANTED)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002603 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2604 }
2605
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002606 return runFromBinderBlocking(() -> {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002607 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002608 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07002609
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002610 p.sendExtraCommand(command, extras);
2611 return true;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002612 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002613 }
2614
Nick Pellye0fd6932012-07-11 10:26:13 -07002615 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002616 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002617 if (Binder.getCallingUid() != Process.myUid()) {
2618 throw new SecurityException(
2619 "calling sendNiResponse from outside of the system is not allowed");
2620 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002621 try {
2622 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002623 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002624 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002625 return false;
2626 }
2627 }
2628
Nick Pellye0fd6932012-07-11 10:26:13 -07002629 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002630 public ProviderProperties getProviderProperties(String provider) throws RemoteException {
Victoria Lease37425c32012-10-16 16:08:48 -07002631 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
2632 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002634 return runFromBinderBlocking(() -> {
2635 LocationProvider p = mProvidersByName.get(provider);
2636 if (p == null) return null;
2637 return p.getProperties();
2638 });
Jason Monkb71218a2015-06-17 14:44:39 -04002639 }
2640
Wei Wang980b7c22018-12-06 17:53:00 -08002641 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002642 public String getNetworkProviderPackage() throws RemoteException {
2643 return runFromBinderBlocking(() -> {
2644 LocationProvider p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
Wei Wang980b7c22018-12-06 17:53:00 -08002645
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002646 if (p == null) {
2647 return null;
Maggie2a9409e2018-03-21 11:47:28 -07002648 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002649 if (p.mProvider instanceof LocationProviderProxy) {
2650 return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
2651 }
2652 return null;
2653 });
Maggie2a9409e2018-03-21 11:47:28 -07002654 }
2655
Maggie2a9409e2018-03-21 11:47:28 -07002656 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002657 public void setLocationControllerExtraPackage(String packageName) throws RemoteException {
2658 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2659 Manifest.permission.LOCATION_HARDWARE + " permission required");
2660
2661 runFromBinderBlocking(() -> mLocationControllerExtraPackage = packageName);
2662 }
2663
2664 @Override
2665 public String getLocationControllerExtraPackage() throws RemoteException {
2666 return runFromBinderBlocking(() -> mLocationControllerExtraPackage);
2667 }
2668
2669 @Override
2670 public void setLocationControllerExtraPackageEnabled(boolean enabled) throws RemoteException {
2671 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2672 Manifest.permission.LOCATION_HARDWARE + " permission required");
2673 runFromBinderBlocking(() -> mLocationControllerExtraPackageEnabled = enabled);
2674 }
2675
2676 @Override
2677 public boolean isLocationControllerExtraPackageEnabled() throws RemoteException {
2678 return runFromBinderBlocking(() -> mLocationControllerExtraPackageEnabled
2679 && (mLocationControllerExtraPackage != null));
2680 }
2681
2682 @Override
2683 public boolean isLocationEnabledForUser(int userId) throws RemoteException {
2684 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
2685 if (UserHandle.getCallingUserId() != userId) {
2686 mContext.enforceCallingOrSelfPermission(
2687 Manifest.permission.INTERACT_ACROSS_USERS,
2688 "Requires INTERACT_ACROSS_USERS permission");
2689 }
2690
2691 return runFromBinderBlocking(() -> isLocationEnabledForUserInternal(userId));
2692 }
2693
2694 private boolean isLocationEnabledForUserInternal(int userId) {
2695 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
2696
2697 final String allowedProviders = Settings.Secure.getStringForUser(
2698 mContext.getContentResolver(),
2699 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2700 userId);
2701 if (allowedProviders == null) {
2702 return false;
2703 }
2704 final List<String> providerList = Arrays.asList(allowedProviders.split(","));
2705
2706 for (String provider : mRealProviders.keySet()) {
2707 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2708 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2709 continue;
2710 }
2711 if (providerList.contains(provider)) {
2712 return true;
2713 }
2714 }
2715 return false;
2716 }
2717
2718 @Override
2719 public void setLocationEnabledForUser(boolean enabled, int userId) throws RemoteException {
Chad Brubaker90f391f2018-10-19 10:26:19 -07002720 mContext.enforceCallingOrSelfPermission(
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002721 android.Manifest.permission.WRITE_SECURE_SETTINGS,
2722 "Requires WRITE_SECURE_SETTINGS permission");
Maggie2a9409e2018-03-21 11:47:28 -07002723
2724 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002725 if (UserHandle.getCallingUserId() != userId) {
2726 mContext.enforceCallingOrSelfPermission(
2727 Manifest.permission.INTERACT_ACROSS_USERS,
2728 "Requires INTERACT_ACROSS_USERS permission");
Maggie2a9409e2018-03-21 11:47:28 -07002729 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002730
2731 runFromBinderBlocking(() -> {
2732 final Set<String> allRealProviders = mRealProviders.keySet();
2733 // Update all providers on device plus gps and network provider when disabling
2734 // location
2735 Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
2736 allProvidersSet.addAll(allRealProviders);
2737 // When disabling location, disable gps and network provider that could have been
2738 // enabled by location mode api.
2739 if (!enabled) {
2740 allProvidersSet.add(LocationManager.GPS_PROVIDER);
2741 allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
2742 }
2743 if (allProvidersSet.isEmpty()) {
2744 return;
2745 }
2746 // to ensure thread safety, we write the provider name with a '+' or '-'
2747 // and let the SettingsProvider handle it rather than reading and modifying
2748 // the list of enabled providers.
2749 final String prefix = enabled ? "+" : "-";
2750 StringBuilder locationProvidersAllowed = new StringBuilder();
2751 for (String provider : allProvidersSet) {
2752 if (provider.equals(LocationManager.PASSIVE_PROVIDER)
2753 || provider.equals(LocationManager.FUSED_PROVIDER)) {
2754 continue;
2755 }
2756 locationProvidersAllowed.append(prefix);
2757 locationProvidersAllowed.append(provider);
2758 locationProvidersAllowed.append(",");
2759 }
2760 // Remove the trailing comma
2761 locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
2762 Settings.Secure.putStringForUser(
2763 mContext.getContentResolver(),
2764 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
2765 locationProvidersAllowed.toString(),
2766 userId);
2767 });
Maggie2a9409e2018-03-21 11:47:28 -07002768 }
2769
Maggie2a9409e2018-03-21 11:47:28 -07002770 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002771 public boolean isProviderEnabledForUser(String providerName, int userId)
2772 throws RemoteException {
Maggie2a9409e2018-03-21 11:47:28 -07002773 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002774 if (UserHandle.getCallingUserId() != userId) {
2775 mContext.enforceCallingOrSelfPermission(
2776 Manifest.permission.INTERACT_ACROSS_USERS,
2777 "Requires INTERACT_ACROSS_USERS permission");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002778 }
2779
Maggie2a9409e2018-03-21 11:47:28 -07002780 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2781 // so we discourage its use
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002782 if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002783
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002784 if (!isLocationEnabledForUser(userId)) {
2785 return false;
Maggie2a9409e2018-03-21 11:47:28 -07002786 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002787
2788 return runFromBinderBlocking(() -> {
2789 LocationProvider provider = mProvidersByName.get(providerName);
2790 return provider != null && provider.isEnabled();
2791 });
Maggie2a9409e2018-03-21 11:47:28 -07002792 }
2793
Maggie2a9409e2018-03-21 11:47:28 -07002794 @Override
2795 public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002796 return false;
Maggieaa080f92018-01-04 15:35:11 -08002797 }
2798
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002799 private boolean isUidALocationProvider(int uid) {
2800 if (uid == Process.SYSTEM_UID) {
2801 return true;
2802 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002803
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002804 for (LocationProviderProxy proxy : mProxyProviders) {
David Christie1f141c12014-05-14 15:11:15 -07002805 if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true;
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002806 }
2807 return false;
2808 }
2809
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002810 private void checkCallerIsProvider() {
2811 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
Maggieaa080f92018-01-04 15:35:11 -08002812 == PERMISSION_GRANTED) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002813 return;
2814 }
2815
2816 // Previously we only used the INSTALL_LOCATION_PROVIDER
2817 // check. But that is system or signature
2818 // protection level which is not flexible enough for
2819 // providers installed oustide the system image. So
2820 // also allow providers with a UID matching the
2821 // currently bound package name
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002822 if (isUidALocationProvider(Binder.getCallingUid())) {
2823 return;
2824 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002825
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002826 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
2827 "or UID of a currently bound location provider");
2828 }
2829
David Christie1f141c12014-05-14 15:11:15 -07002830 private boolean doesUidHavePackage(int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002831 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002832 return false;
2833 }
David Christie1f141c12014-05-14 15:11:15 -07002834 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2835 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002836 return false;
2837 }
David Christie1f141c12014-05-14 15:11:15 -07002838 for (String name : packageNames) {
2839 if (packageName.equals(name)) {
2840 return true;
2841 }
2842 }
2843 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002844 }
2845
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002846 // TODO: will be removed in future
Nick Pellye0fd6932012-07-11 10:26:13 -07002847 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05002848 public void reportLocation(Location location, boolean passive) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002849 throw new IllegalStateException("operation unsupported");
Mike Lockwood4e50b782009-04-03 08:24:43 -07002850 }
2851
Laurent Tu75defb62012-11-01 16:21:52 -07002852 private static boolean shouldBroadcastSafe(
2853 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002854 // Always broadcast the first update
2855 if (lastLoc == null) {
2856 return true;
2857 }
2858
Nick Pellyf1be6862012-05-15 10:53:42 -07002859 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002860 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002861 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2862 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002863 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002864 return false;
2865 }
2866
2867 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002868 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002869 if (minDistance > 0.0) {
2870 if (loc.distanceTo(lastLoc) <= minDistance) {
2871 return false;
2872 }
2873 }
2874
Laurent Tu75defb62012-11-01 16:21:52 -07002875 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002876 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002877 return false;
2878 }
2879
2880 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002881 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002882 }
2883
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002884 private void handleLocationChanged(Location location, boolean passive) {
2885 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
2886
2887 // create a working copy of the incoming Location so that the service can modify it without
2888 // disturbing the caller's copy
2889 Location myLocation = new Location(location);
2890 String pr = myLocation.getProvider();
2891
2892 // set "isFromMockProvider" bit if location came from a mock provider. we do not clear this
2893 // bit if location did not come from a mock provider because passive/fused providers can
2894 // forward locations from mock providers, and should not grant them legitimacy in doing so.
2895 if (!myLocation.isFromMockProvider() && isMockProvider(pr)) {
2896 myLocation.setIsFromMockProvider(true);
2897 }
2898
2899 if (!passive) {
2900 // notify passive provider of the new location
2901 mPassiveProvider.updateLocation(myLocation);
2902 }
2903
2904 if (D) Log.d(TAG, "incoming location: " + myLocation);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002905 long now = SystemClock.elapsedRealtime();
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002906 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : myLocation.getProvider());
Laurent Tu60ec50a2012-10-04 17:00:10 -07002907 // Skip if the provider is unknown.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002908 LocationProvider p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002909 if (p == null) return;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002910 updateLastLocation(myLocation, provider);
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002911 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002912 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07002913 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002914 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
2915 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07002916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002917
David Christie1b9b7b12013-04-15 15:31:11 -07002918 // Update last known coarse interval location if enough time has passed.
2919 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider);
2920 if (lastLocationCoarseInterval == null) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002921 lastLocationCoarseInterval = new Location(myLocation);
David Christie1b9b7b12013-04-15 15:31:11 -07002922 mLastLocationCoarseInterval.put(provider, lastLocationCoarseInterval);
2923 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002924 long timeDiffNanos = myLocation.getElapsedRealtimeNanos()
David Christie1b9b7b12013-04-15 15:31:11 -07002925 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2926 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002927 lastLocationCoarseInterval.set(myLocation);
David Christie1b9b7b12013-04-15 15:31:11 -07002928 }
2929 // Don't ever return a coarse location that is more recent than the allowed update
2930 // interval (i.e. don't allow an app to keep registering and unregistering for
2931 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002932 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07002933 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
2934
Laurent Tu60ec50a2012-10-04 17:00:10 -07002935 // Skip if there are no UpdateRecords for this provider.
2936 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2937 if (records == null || records.size() == 0) return;
2938
Victoria Lease09016ab2012-09-16 12:33:15 -07002939 // Fetch coarse location
2940 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07002941 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002942 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
2943 }
2944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002945 // Fetch latest status update time
2946 long newStatusUpdateTime = p.getStatusUpdateTime();
2947
David Christie2ff96af2014-01-30 16:09:37 -08002948 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002949 Bundle extras = new Bundle();
2950 int status = p.getStatus(extras);
2951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002952 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002953 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07002954
Soonil Nagarkar94749f72018-11-08 11:46:43 -08002955 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002956 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002957 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07002958 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07002959
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002960 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
2961 if (!isCurrentProfile(receiverUserId)
2962 && !isUidALocationProvider(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002963 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07002964 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07002965 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002966 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07002967 }
2968 continue;
2969 }
2970
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002971 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08002972 if (D) {
2973 Log.d(TAG, "skipping loc update for blacklisted app: " +
2974 receiver.mIdentity.mPackageName);
2975 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07002976 continue;
2977 }
2978
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002979 if (!reportLocationAccessNoThrow(
2980 receiver.mIdentity.mPid,
2981 receiver.mIdentity.mUid,
2982 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002983 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08002984 if (D) {
2985 Log.d(TAG, "skipping loc update for no op app: " +
2986 receiver.mIdentity.mPackageName);
2987 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002988 continue;
2989 }
2990
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002991 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07002992 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2993 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002994 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07002995 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002996 }
Victoria Lease09016ab2012-09-16 12:33:15 -07002997 if (notifyLocation != null) {
2998 Location lastLoc = r.mLastFixBroadcast;
Laurent Tu75defb62012-11-01 16:21:52 -07002999 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003000 if (lastLoc == null) {
3001 lastLoc = new Location(notifyLocation);
3002 r.mLastFixBroadcast = lastLoc;
3003 } else {
3004 lastLoc.set(notifyLocation);
3005 }
3006 if (!receiver.callLocationChangedLocked(notifyLocation)) {
3007 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
3008 receiverDead = true;
3009 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003010 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003011 }
3012 }
3013
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003014 // TODO: location provider status callbacks have been disabled and deprecated, and are
3015 // guarded behind this setting now. should be removed completely post-Q
3016 if (Settings.Global.getInt(mContext.getContentResolver(),
3017 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
3018 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3019 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003020 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003021
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003022 r.mLastStatusBroadcast = newStatusUpdateTime;
3023 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
3024 receiverDead = true;
3025 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3026 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003027 }
3028 }
3029
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003030 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003031 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003032 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003033 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003034 }
3035 deadUpdateRecords.add(r);
3036 }
3037 // track dead receivers
3038 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003039 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003040 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003041 }
3042 if (!deadReceivers.contains(receiver)) {
3043 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003044 }
3045 }
3046 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003047
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003048 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003049 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003050 for (Receiver receiver : deadReceivers) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003051 removeUpdates(receiver);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003052 }
3053 }
3054 if (deadUpdateRecords != null) {
3055 for (UpdateRecord r : deadUpdateRecords) {
3056 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003057 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003058 applyRequirements(provider);
Victoria Lease8b38b292012-12-04 15:04:43 -08003059 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003060 }
3061
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003062 private void updateLastLocation(Location location, String provider) {
3063 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
3064
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003065 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3066 Location lastNoGPSLocation;
3067 Location lastLocation = mLastLocation.get(provider);
3068 if (lastLocation == null) {
3069 lastLocation = new Location(provider);
3070 mLastLocation.put(provider, lastLocation);
3071 } else {
3072 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3073 if (noGPSLocation == null && lastNoGPSLocation != null) {
3074 // New location has no no-GPS location: adopt last no-GPS location. This is set
3075 // directly into location because we do not want to notify COARSE clients.
3076 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3077 }
3078 }
3079 lastLocation.set(location);
3080 }
3081
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003082 private boolean isMockProvider(String provider) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003083 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
3084 return mMockProviders.containsKey(provider);
Victoria Lease54ca7ae2013-01-08 09:39:50 -08003085 }
3086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003087 // Geocoder
3088
Nick Pellye0fd6932012-07-11 10:26:13 -07003089 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003090 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003091 return mGeocodeProvider != null;
3092 }
3093
Nick Pellye0fd6932012-07-11 10:26:13 -07003094 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003096 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003097 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003098 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3099 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003100 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003101 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 }
3103
Mike Lockwooda55c3212009-04-15 11:10:11 -04003104
Nick Pellye0fd6932012-07-11 10:26:13 -07003105 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003106 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003107 double lowerLeftLatitude, double lowerLeftLongitude,
3108 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003109 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003110
3111 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003112 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3113 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3114 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003115 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003116 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117 }
3118
3119 // Mock Providers
3120
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003121 private boolean canCallerAccessMockLocation(String opPackageName) {
3122 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3123 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003124 }
3125
Nick Pellye0fd6932012-07-11 10:26:13 -07003126 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003127 public void addTestProvider(String name, ProviderProperties properties, String opPackageName)
3128 throws RemoteException {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003129 if (!canCallerAccessMockLocation(opPackageName)) {
3130 return;
3131 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003132
Mike Lockwooda4903f22010-02-17 06:42:23 -05003133 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
3134 throw new IllegalArgumentException("Cannot mock the passive location provider");
3135 }
3136
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003137 runFromBinderBlocking(() -> {
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003138 // remove the real provider if we are replacing GPS or network provider
3139 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07003140 || LocationManager.NETWORK_PROVIDER.equals(name)
3141 || LocationManager.FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003142 LocationProvider p = mProvidersByName.get(name);
Mike Lockwoodd03ff942010-02-09 08:46:14 -05003143 if (p != null) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003144 removeProvider(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003145 }
3146 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003147 addTestProvider(name, properties);
3148 return null;
3149 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 }
3151
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003152 private void addTestProvider(String name, ProviderProperties properties) {
3153 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
3154
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003155 if (mProvidersByName.get(name) != null) {
3156 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
3157 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003158
3159 LocationProvider provider = new LocationProvider(name);
3160 MockProvider mockProvider = new MockProvider(provider, properties);
3161
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003162 addProvider(provider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003163 mMockProviders.put(name, mockProvider);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003164 mLastLocation.put(name, null);
3165 mLastLocationCoarseInterval.put(name, null);
3166 }
3167
Nick Pellye0fd6932012-07-11 10:26:13 -07003168 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003169 public void removeTestProvider(String provider, String opPackageName) throws RemoteException {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003170 if (!canCallerAccessMockLocation(opPackageName)) {
3171 return;
3172 }
3173
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003174 runFromBinderBlocking(() -> {
You Kima6d0b6f2012-10-28 03:58:44 +09003175 MockProvider mockProvider = mMockProviders.remove(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003176 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003177 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3178 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003179
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003180 removeProvider(mProvidersByName.get(provider));
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003181
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003182 // reinstate real provider if available
3183 LocationProvider realProvider = mRealProviders.get(provider);
3184 if (realProvider != null) {
3185 addProvider(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003186 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003187 mLastLocation.put(provider, null);
3188 mLastLocationCoarseInterval.put(provider, null);
3189 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 }
3191
Nick Pellye0fd6932012-07-11 10:26:13 -07003192 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003193 public void setTestProviderLocation(String provider, Location loc, String opPackageName)
3194 throws RemoteException {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003195 if (!canCallerAccessMockLocation(opPackageName)) {
3196 return;
3197 }
3198
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003199 runFromBinderBlocking(() -> {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003200 MockProvider mockProvider = mMockProviders.get(provider);
3201 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003202 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3203 }
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003204
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003205 // Ensure that the location is marked as being mock. There's some logic to do this
3206 // in handleLocationChanged(), but it fails if loc has the wrong provider
3207 // (b/33091107).
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003208 Location mock = new Location(loc);
3209 mock.setIsFromMockProvider(true);
3210
3211 if (!TextUtils.isEmpty(loc.getProvider()) && !provider.equals(loc.getProvider())) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003212 // The location has an explicit provider that is different from the mock
3213 // provider name. The caller may be trying to fool us via bug 33091107.
Tom O'Neilla206a0f2016-12-15 10:26:28 -08003214 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3215 provider + "!=" + loc.getProvider());
3216 }
3217
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003218 mockProvider.setLocation(mock);
3219 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 }
3221
Nick Pellye0fd6932012-07-11 10:26:13 -07003222 @Override
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003223 public void setTestProviderEnabled(String provider, boolean enabled, String opPackageName)
3224 throws RemoteException {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003225 if (!canCallerAccessMockLocation(opPackageName)) {
3226 return;
3227 }
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003228
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003229 runFromBinderBlocking(() -> {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003230 MockProvider mockProvider = mMockProviders.get(provider);
3231 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003232 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3233 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003234 mockProvider.setEnabled(enabled);
3235 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236 }
3237
Nick Pellye0fd6932012-07-11 10:26:13 -07003238 @Override
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003239 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime,
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003240 String opPackageName) throws RemoteException {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003241 if (!canCallerAccessMockLocation(opPackageName)) {
3242 return;
3243 }
3244
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003245 runFromBinderBlocking(() -> {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003246 MockProvider mockProvider = mMockProviders.get(provider);
3247 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003248 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
3249 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07003250 mockProvider.setStatus(status, extras, updateTime);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003251 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003252 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003253
3254 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003255 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003256 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003257
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003258 Runnable dump = () -> {
Siddharth Raybb608c82017-03-16 11:33:34 -07003259 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3260 if (mGnssMetricsProvider != null) {
3261 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3262 }
3263 return;
3264 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003265 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003266 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003267 for (Receiver receiver : mReceivers.values()) {
3268 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003269 }
David Christie2ff96af2014-01-30 16:09:37 -08003270 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003271 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3272 pw.println(" " + entry.getKey() + ":");
3273 for (UpdateRecord record : entry.getValue()) {
3274 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003275 }
3276 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003277 pw.println(" Active GnssMeasurement Listeners:");
3278 for (Identity identity : mGnssMeasurementsListeners.values()) {
3279 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3280 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3281 }
3282 pw.println(" Active GnssNavigationMessage Listeners:");
3283 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3284 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3285 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3286 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003287 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003288 for (LocationProvider provider : mProviders) {
3289 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003290 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003291 + ((LocationProviderProxy) provider.mProvider)
3292 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003293 }
3294 }
David Christie2ff96af2014-01-30 16:09:37 -08003295 pw.println(" Historical Records by Provider:");
3296 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3297 : mRequestStatistics.statistics.entrySet()) {
3298 PackageProviderKey key = entry.getKey();
3299 PackageStatistics stats = entry.getValue();
3300 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3301 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003302 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003303 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3304 String provider = entry.getKey();
3305 Location location = entry.getValue();
3306 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003308
David Christie1b9b7b12013-04-15 15:31:11 -07003309 pw.println(" Last Known Locations Coarse Intervals:");
3310 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3311 String provider = entry.getKey();
3312 Location location = entry.getValue();
3313 pw.println(" " + provider + ": " + location);
3314 }
3315
Nick Pellye0fd6932012-07-11 10:26:13 -07003316 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003317
Nick Pelly4035f5a2012-08-17 14:43:49 -07003318 pw.append(" ");
3319 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 if (mMockProviders.size() > 0) {
3321 pw.println(" Mock Providers:");
3322 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003323 i.getValue().dump(fd, pw, args);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003324 }
3325 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003326
Wei Wang980b7c22018-12-06 17:53:00 -08003327 if (mLocationControllerExtraPackage != null) {
3328 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
3329 + " enabled: " + mLocationControllerExtraPackageEnabled);
3330 }
3331
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003332 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3333 pw.println(" Throttling Whitelisted Packages:");
3334 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3335 pw.println(" " + packageName);
3336 }
3337 }
3338
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003339 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003340 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003341
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003342 if (args.length > 0 && "short".equals(args[0])) {
3343 return;
3344 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003345 for (LocationProvider provider : mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003346 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003347 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003348 if (mGnssBatchingInProgress) {
3349 pw.println(" GNSS batching in progress");
3350 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08003351 };
3352
3353 FutureTask<Void> task = new FutureTask<>(dump, null);
3354 mHandler.postAtFrontOfQueue(task);
3355 try {
3356 task.get();
3357 } catch (InterruptedException | ExecutionException e) {
3358 pw.println("error dumping: " + e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003359 }
3360 }
3361}