blob: 2543f5209dd92ac33f49289c47b31a50aad3fbcf [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 Nagarkar90da1ab2019-01-04 16:26:59 -080020import static android.location.LocationManager.FUSED_PROVIDER;
21import static android.location.LocationManager.GPS_PROVIDER;
22import static android.location.LocationManager.NETWORK_PROVIDER;
23import static android.location.LocationManager.PASSIVE_PROVIDER;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070024import static android.location.LocationProvider.AVAILABLE;
Soonil Nagarkar94749f72018-11-08 11:46:43 -080025import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS;
Maggieaa080f92018-01-04 15:35:11 -080026
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080027import static com.android.internal.util.Preconditions.checkNotNull;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070028import static com.android.internal.util.Preconditions.checkState;
29
Wei Wang980b7c22018-12-06 17:53:00 -080030import android.Manifest;
Wyatt Rileycf879db2017-01-12 13:57:38 -080031import android.annotation.NonNull;
Wyatt Riley49097c02018-03-15 09:14:43 -070032import android.annotation.Nullable;
Maggieaa080f92018-01-04 15:35:11 -080033import android.app.ActivityManager;
34import android.app.AppOpsManager;
35import android.app.PendingIntent;
36import android.content.BroadcastReceiver;
Maggieaa080f92018-01-04 15:35:11 -080037import android.content.Context;
38import android.content.Intent;
39import android.content.IntentFilter;
40import android.content.pm.ApplicationInfo;
41import android.content.pm.PackageInfo;
42import android.content.pm.PackageManager;
43import android.content.pm.PackageManager.NameNotFoundException;
44import android.content.pm.PackageManagerInternal;
45import android.content.pm.ResolveInfo;
46import android.content.pm.Signature;
47import android.content.res.Resources;
48import android.database.ContentObserver;
Maggieaa080f92018-01-04 15:35:11 -080049import android.location.Address;
50import android.location.Criteria;
51import android.location.GeocoderParams;
52import android.location.Geofence;
gomo226b7b72018-12-12 16:49:39 -080053import android.location.GnssMeasurementCorrections;
Maggieaa080f92018-01-04 15:35:11 -080054import android.location.IBatchedLocationCallback;
55import android.location.IGnssMeasurementsListener;
56import android.location.IGnssNavigationMessageListener;
57import android.location.IGnssStatusListener;
Maggieaa080f92018-01-04 15:35:11 -080058import android.location.IGpsGeofenceHardware;
59import android.location.ILocationListener;
60import android.location.ILocationManager;
61import android.location.INetInitiatedListener;
62import android.location.Location;
63import android.location.LocationManager;
Maggieaa080f92018-01-04 15:35:11 -080064import android.location.LocationRequest;
65import android.os.Binder;
66import android.os.Bundle;
67import android.os.Handler;
68import android.os.IBinder;
69import android.os.Looper;
Maggieaa080f92018-01-04 15:35:11 -080070import android.os.PowerManager;
71import android.os.Process;
72import android.os.RemoteException;
73import android.os.SystemClock;
74import android.os.UserHandle;
75import android.os.UserManager;
76import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000077import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080078import android.provider.Settings;
79import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080080import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080081import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080082import android.util.EventLog;
83import android.util.Log;
84import android.util.Slog;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -070085
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080086import com.android.internal.annotations.GuardedBy;
destradaaea8a8a62014-06-23 18:19:03 -070087import com.android.internal.content.PackageMonitor;
88import com.android.internal.location.ProviderProperties;
89import com.android.internal.location.ProviderRequest;
90import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070091import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060092import com.android.internal.util.DumpUtils;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080093import com.android.internal.util.Preconditions;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070094import com.android.server.location.AbstractLocationProvider;
destradaaea8a8a62014-06-23 18:19:03 -070095import com.android.server.location.GeocoderProxy;
96import com.android.server.location.GeofenceManager;
97import com.android.server.location.GeofenceProxy;
Yu-Han Yang3557cc72018-03-21 12:48:36 -070098import com.android.server.location.GnssBatchingProvider;
Lifu Tang818aa2c2016-02-01 01:52:00 -080099import com.android.server.location.GnssLocationProvider;
100import com.android.server.location.GnssMeasurementsProvider;
101import com.android.server.location.GnssNavigationMessageProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800102import com.android.server.location.GnssStatusListenerHelper;
destradaaea8a8a62014-06-23 18:19:03 -0700103import com.android.server.location.LocationBlacklist;
104import com.android.server.location.LocationFudger;
destradaaea8a8a62014-06-23 18:19:03 -0700105import com.android.server.location.LocationProviderProxy;
106import com.android.server.location.LocationRequestStatistics;
107import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
108import com.android.server.location.LocationRequestStatistics.PackageStatistics;
109import com.android.server.location.MockProvider;
110import com.android.server.location.PassiveProvider;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -0700111
Mike Lockwood43e33f22010-03-26 10:41:48 -0400112import java.io.FileDescriptor;
113import java.io.PrintWriter;
114import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700115import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400116import java.util.HashMap;
117import java.util.HashSet;
118import java.util.List;
119import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800120import java.util.Map.Entry;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800121import java.util.NoSuchElementException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122
123/**
124 * The service class that manages LocationProviders and issues location
125 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800127public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800129 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700130
Olivier Gaillard7a222662017-11-20 16:07:24 +0000131 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
Victoria Lease37425c32012-10-16 16:08:48 -0700133 // Location resolution level: no location data whatsoever
134 private static final int RESOLUTION_LEVEL_NONE = 0;
135 // Location resolution level: coarse location data only
136 private static final int RESOLUTION_LEVEL_COARSE = 1;
137 // Location resolution level: fine location data
138 private static final int RESOLUTION_LEVEL_FINE = 2;
139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700141 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700142
143 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700144 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700145 private static final String FUSED_LOCATION_SERVICE_ACTION =
146 "com.android.location.service.FusedLocationProvider";
147
David Christie1b9b7b12013-04-15 15:31:11 -0700148 private static final long NANOS_PER_MILLI = 1000000L;
149
David Christie0b837452013-07-29 16:02:13 -0700150 // The maximum interval a location request can have and still be considered "high power".
151 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
152
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700153 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800154 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700155
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800156 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800157 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800158
Wei Wangdd070f22018-06-21 11:29:40 -0700159 // Default value for maximum age of last location returned to applications with foreground-only
160 // location permissions.
161 private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
162
Nick Pellyf1be6862012-05-15 10:53:42 -0700163 // Location Providers may sometimes deliver location updates
164 // slightly faster that requested - provide grace period so
165 // we don't unnecessarily filter events that are otherwise on
166 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
170
Soonil Nagarkar68257742019-01-09 19:42:34 +0000171 private final Object mLock = new Object();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800172 private final Context mContext;
173 private final Handler mHandler;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800175 private AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700176 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700177 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800178 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700179 private UserManager mUserManager;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800180
181 private GeofenceManager mGeofenceManager;
182 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 private GeocoderProxy mGeocodeProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800184 private GnssStatusListenerHelper mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 private INetInitiatedListener mNetInitiatedListener;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700186 private PassiveProvider mPassiveProvider; // track passive provider for special cases
187 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800188 private GnssMeasurementsProvider mGnssMeasurementsProvider;
189 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800190 @GuardedBy("mLock")
Wei Wang980b7c22018-12-06 17:53:00 -0800191 private String mLocationControllerExtraPackage;
192 private boolean mLocationControllerExtraPackageEnabled;
Wei Liu5241a4c2015-05-11 14:00:36 -0700193 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700194
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800195 // list of currently active providers
196 @GuardedBy("mLock")
197 private final ArrayList<LocationProvider> mProviders = new ArrayList<>();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000198
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800199 // list of non-mock providers, so that when mock providers replace real providers, they can be
200 // later re-replaced
201 @GuardedBy("mLock")
202 private final ArrayList<LocationProvider> mRealProviders = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800204 @GuardedBy("mLock")
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800205 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700206 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800207 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700208
David Christie2ff96af2014-01-30 16:09:37 -0800209 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
210
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700211 // mapping from provider name to last known location
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800212 @GuardedBy("mLock")
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800213 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
David Christie1b9b7b12013-04-15 15:31:11 -0700215 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
216 // locations stored here are not fudged for coarse permissions.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800217 @GuardedBy("mLock")
David Christie1b9b7b12013-04-15 15:31:11 -0700218 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800219 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700220
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800221 private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800222
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800223 @GuardedBy("mLock")
Wyatt Riley11cc7492018-01-17 08:48:27 -0800224 private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800225
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800226 @GuardedBy("mLock")
Wyatt Riley11cc7492018-01-17 08:48:27 -0800227 private final ArrayMap<IBinder, Identity>
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800228 mGnssNavigationMessageListeners = new ArrayMap<>();
229
Victoria Lease38389b62012-09-30 11:44:22 -0700230 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700231 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800232 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700233
Lifu Tang9363b942016-02-16 18:07:00 -0800234 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800235
Siddharth Raybb608c82017-03-16 11:33:34 -0700236 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700237
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700238 private GnssBatchingProvider mGnssBatchingProvider;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800239 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800240 private IBatchedLocationCallback mGnssBatchingCallback;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800241 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800242 private LinkedCallback mGnssBatchingDeathCallback;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800243 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800244 private boolean mGnssBatchingInProgress = false;
245
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700246 public LocationManagerService(Context context) {
247 super();
248 mContext = context;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800249 mHandler = BackgroundThread.getHandler();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800250
Svet Ganovadc1cf42015-06-15 16:36:24 -0700251 // Let the package manager query which are the default location
252 // providers as they get certain permissions granted by default.
253 PackageManagerInternal packageManagerInternal = LocalServices.getService(
254 PackageManagerInternal.class);
255 packageManagerInternal.setLocationPackagesProvider(
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700256 userId -> mContext.getResources().getStringArray(
257 com.android.internal.R.array.config_locationProviderPackageNames));
Wei Wangffb94e62019-01-14 00:05:45 -0800258 packageManagerInternal.setLocationExtraPackagesProvider(
259 userId -> mContext.getResources().getStringArray(
260 com.android.internal.R.array.config_locationExtraPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700261
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700262 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700263 }
264
Svetoslav Ganova0027152013-06-25 14:59:53 -0700265 public void systemRunning() {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000266 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800267 initializeLocked();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800268 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800269 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700270
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800271 @GuardedBy("mLock")
272 private void initializeLocked() {
273 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
274 mPackageManager = mContext.getPackageManager();
275 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
276 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
277 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
278
279 mLocationFudger = new LocationFudger(mContext, mHandler);
280 mBlacklist = new LocationBlacklist(mContext, mHandler);
281 mBlacklist.init();
282 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
283
284 // prepare providers
285 initializeProvidersLocked();
286
287 // add listeners
288 mAppOps.startWatchingMode(
289 AppOpsManager.OP_COARSE_LOCATION,
290 null,
291 AppOpsManager.WATCH_FOREGROUND_CHANGES,
292 new AppOpsManager.OnOpChangedInternalListener() {
293 public void onOpChanged(int op, String packageName) {
294 synchronized (mLock) {
295 onAppOpChangedLocked();
296 }
297 }
298 });
299 mPackageManager.addOnPermissionsChangeListener(
300 uid -> {
301 synchronized (mLock) {
302 onPermissionsChangedLocked();
303 }
304 });
305
306 mActivityManager.addOnUidImportanceListener(
307 (uid, importance) -> {
308 synchronized (mLock) {
309 onUidImportanceChangedLocked(uid, importance);
310 }
311 },
312 FOREGROUND_IMPORTANCE_CUTOFF);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700313 mContext.getContentResolver().registerContentObserver(
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800314 Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), true,
315 new ContentObserver(mHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800316 @Override
317 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000318 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800319 onLocationModeChangedLocked(true);
320 }
321 }
322 }, UserHandle.USER_ALL);
323 mContext.getContentResolver().registerContentObserver(
324 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
325 new ContentObserver(mHandler) {
326 @Override
327 public void onChange(boolean selfChange) {
328 synchronized (mLock) {
329 onProviderAllowedChangedLocked(true);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000330 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800331 }
332 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800333 mContext.getContentResolver().registerContentObserver(
334 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
335 true,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800336 new ContentObserver(mHandler) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800337 @Override
338 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000339 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800340 onBackgroundThrottleIntervalChangedLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000341 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800342 }
343 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800344 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800345 Settings.Global.getUriFor(
346 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
347 true,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800348 new ContentObserver(mHandler) {
gomo48f1a642017-11-10 20:35:46 -0800349 @Override
350 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000351 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800352 onBackgroundThrottleWhitelistChangedLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000353 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800354 }
gomo48f1a642017-11-10 20:35:46 -0800355 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700356
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800357 new PackageMonitor() {
358 @Override
359 public void onPackageDisappeared(String packageName, int reason) {
360 synchronized (mLock) {
361 LocationManagerService.this.onPackageDisappearedLocked(packageName);
362 }
363 }
364 }.register(mContext, mHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700365
Victoria Lease38389b62012-09-30 11:44:22 -0700366 IntentFilter intentFilter = new IntentFilter();
367 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700368 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
369 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700370
371 mContext.registerReceiverAsUser(new BroadcastReceiver() {
372 @Override
373 public void onReceive(Context context, Intent intent) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800374 synchronized (mLock) {
375 String action = intent.getAction();
376 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
377 onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
378 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
379 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
380 onUserProfilesChangedLocked();
381 }
Victoria Lease38389b62012-09-30 11:44:22 -0700382 }
383 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800384 }, UserHandle.ALL, intentFilter, null, mHandler);
385
386 // switching the user from null to system here performs the bulk of the initialization work.
387 // the user being changed will cause a reload of all user specific settings, which causes
388 // provider initialization, and propagates changes until a steady state is reached
389 mCurrentUserId = UserHandle.USER_NULL;
390 onUserChangedLocked(UserHandle.USER_SYSTEM);
391
392 // initialize in-memory settings values
393 onBackgroundThrottleWhitelistChangedLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700394 }
395
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800396 @GuardedBy("mLock")
397 private void onAppOpChangedLocked() {
398 for (Receiver receiver : mReceivers.values()) {
399 receiver.updateMonitoring(true);
400 }
401 for (LocationProvider p : mProviders) {
402 applyRequirementsLocked(p);
403 }
404 }
405
406 @GuardedBy("mLock")
407 private void onPermissionsChangedLocked() {
408 for (LocationProvider p : mProviders) {
409 applyRequirementsLocked(p);
410 }
411 }
412
413 @GuardedBy("mLock")
414 private void onLocationModeChangedLocked(boolean broadcast) {
415 for (LocationProvider p : mProviders) {
416 p.onLocationModeChangedLocked();
417 }
418
419 if (broadcast) {
420 mContext.sendBroadcastAsUser(
421 new Intent(LocationManager.MODE_CHANGED_ACTION),
422 UserHandle.ALL);
423 }
424 }
425
426 @GuardedBy("mLock")
427 private void onProviderAllowedChangedLocked(boolean broadcast) {
428 for (LocationProvider p : mProviders) {
429 p.onAllowedChangedLocked();
430 }
431
432 if (broadcast) {
433 mContext.sendBroadcastAsUser(
434 new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
435 UserHandle.ALL);
436 }
437 }
438
439 @GuardedBy("mLock")
440 private void onPackageDisappearedLocked(String packageName) {
441 ArrayList<Receiver> deadReceivers = null;
442
443 for (Receiver receiver : mReceivers.values()) {
444 if (receiver.mIdentity.mPackageName.equals(packageName)) {
445 if (deadReceivers == null) {
446 deadReceivers = new ArrayList<>();
447 }
448 deadReceivers.add(receiver);
449 }
450 }
451
452 // perform removal outside of mReceivers loop
453 if (deadReceivers != null) {
454 for (Receiver receiver : deadReceivers) {
455 removeUpdatesLocked(receiver);
456 }
457 }
458 }
459
460 @GuardedBy("mLock")
461 private void onUidImportanceChangedLocked(int uid, int importance) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700462 boolean foreground = isImportanceForeground(importance);
463 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800464 for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
465 String provider = entry.getKey();
466 for (UpdateRecord record : entry.getValue()) {
467 if (record.mReceiver.mIdentity.mUid == uid
468 && record.mIsForegroundUid != foreground) {
gomo48f1a642017-11-10 20:35:46 -0800469 if (D) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800470 Log.d(TAG, "request from uid " + uid + " is now "
gomo48f1a642017-11-10 20:35:46 -0800471 + (foreground ? "foreground" : "background)"));
472 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800473 record.updateForeground(foreground);
474
475 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
476 affectedProviders.add(provider);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700477 }
478 }
479 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800480 }
481 for (String provider : affectedProviders) {
482 applyRequirementsLocked(provider);
483 }
Anil Admal75b9fd62018-11-28 11:22:50 -0800484
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800485 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
486 Identity callerIdentity = entry.getValue();
487 if (callerIdentity.mUid == uid) {
488 if (D) {
489 Log.d(TAG, "gnss measurements listener from uid " + uid
490 + " is now " + (foreground ? "foreground" : "background)"));
491 }
492 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
493 mGnssMeasurementsProvider.addListener(
494 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
495 callerIdentity.mUid, callerIdentity.mPackageName);
496 } else {
497 mGnssMeasurementsProvider.removeListener(
498 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
499 }
500 }
501 }
502
503 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
504 Identity callerIdentity = entry.getValue();
505 if (callerIdentity.mUid == uid) {
506 if (D) {
507 Log.d(TAG, "gnss navigation message listener from uid "
508 + uid + " is now "
509 + (foreground ? "foreground" : "background)"));
510 }
511 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
512 mGnssNavigationMessageProvider.addListener(
513 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
514 callerIdentity.mUid, callerIdentity.mPackageName);
515 } else {
516 mGnssNavigationMessageProvider.removeListener(
517 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
518 }
519 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700520 }
521 }
522
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800523 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700524 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800525 }
526
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800527 @GuardedBy("mLock")
528 private void onBackgroundThrottleIntervalChangedLocked() {
529 for (LocationProvider provider : mProviders) {
530 applyRequirementsLocked(provider);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000531 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800532 }
533
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800534 @GuardedBy("mLock")
535 private void onBackgroundThrottleWhitelistChangedLocked() {
536 String setting = Settings.Global.getString(
537 mContext.getContentResolver(),
538 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
539 if (setting == null) {
540 setting = "";
541 }
542
543 mBackgroundThrottlePackageWhitelist.clear();
544 mBackgroundThrottlePackageWhitelist.addAll(
545 SystemConfig.getInstance().getAllowUnthrottledLocation());
546 mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(",")));
547
548 for (LocationProvider p : mProviders) {
549 applyRequirementsLocked(p);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000550 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800551 }
552
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800553 @GuardedBy("mLock")
554 private void onUserProfilesChangedLocked() {
555 mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(mCurrentUserId);
556 }
557
558 @GuardedBy("mLock")
559 private boolean isCurrentProfileLocked(int userId) {
560 return ArrayUtils.contains(mCurrentUserProfiles, userId);
561 }
562
563 @GuardedBy("mLock")
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700564 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500565 PackageManager pm = mContext.getPackageManager();
566 String systemPackageName = mContext.getPackageName();
567 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
568
569 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
570 new Intent(FUSED_LOCATION_SERVICE_ACTION),
571 PackageManager.GET_META_DATA, mCurrentUserId);
572 for (ResolveInfo rInfo : rInfos) {
573 String packageName = rInfo.serviceInfo.packageName;
574
575 // Check that the signature is in the list of supported sigs. If it's not in
576 // this list the standard provider binding logic won't bind to it.
577 try {
578 PackageInfo pInfo;
579 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
580 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
581 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
582 ", but has wrong signature, ignoring");
583 continue;
584 }
585 } catch (NameNotFoundException e) {
586 Log.e(TAG, "missing package: " + packageName);
587 continue;
588 }
589
590 // Get the version info
591 if (rInfo.serviceInfo.metaData == null) {
592 Log.w(TAG, "Found fused provider without metadata: " + packageName);
593 continue;
594 }
595
596 int version = rInfo.serviceInfo.metaData.getInt(
597 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
598 if (version == 0) {
599 // This should be the fallback fused location provider.
600
601 // Make sure it's in the system partition.
602 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
603 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
604 continue;
605 }
606
607 // Check that the fallback is signed the same as the OS
608 // as a proxy for coreApp="true"
609 if (pm.checkSignatures(systemPackageName, packageName)
610 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800611 if (D) {
612 Log.d(TAG, "Fallback candidate not signed the same as system: "
613 + packageName);
614 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500615 continue;
616 }
617
618 // Found a valid fallback.
619 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
620 return;
621 } else {
622 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
623 }
624 }
625
626 throw new IllegalStateException("Unable to find a fused location provider that is in the "
627 + "system partition with version 0 and signed with the platform certificate. "
628 + "Such a package is needed to provide a default fused location provider in the "
629 + "event that no other fused location provider has been installed or is currently "
630 + "available. For example, coreOnly boot mode when decrypting the data "
631 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
632 }
633
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800634 @GuardedBy("mLock")
635 private void initializeProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700636 // create a passive location provider, which is always enabled
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800637 LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000638 addProviderLocked(passiveProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800639 mPassiveProvider = new PassiveProvider(passiveProviderManager);
640 passiveProviderManager.attachLocked(mPassiveProvider);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700641
Lifu Tang30f95a72016-01-07 23:20:38 -0800642 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700643 // Create a gps location provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800644 LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
645 mRealProviders.add(gnssProviderManager);
646 addProviderLocked(gnssProviderManager);
647
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700648 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
649 gnssProviderManager,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800650 mHandler.getLooper());
651 gnssProviderManager.attachLocked(gnssProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700652
Lifu Tang9363b942016-02-16 18:07:00 -0800653 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800654 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700655 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800656 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
657 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
Lifu Tang818aa2c2016-02-01 01:52:00 -0800658 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
659 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800660 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 }
662
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700663 /*
664 Load package name(s) containing location provider support.
665 These packages can contain services implementing location providers:
666 Geocoder Provider, Network Location Provider, and
667 Fused Location Provider. They will each be searched for
668 service components implementing these providers.
669 The location framework also has support for installation
670 of new location providers at run-time. The new package does not
671 have to be explicitly listed here, however it must have a signature
672 that matches the signature of at least one package on this list.
673 */
674 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500675 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700676 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800677 if (D) {
678 Log.d(TAG, "certificates for location providers pulled from: " +
679 Arrays.toString(pkgs));
680 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500681
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700682 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700683
684 // bind to network provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800685 LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER, true);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700686 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
687 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700688 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700689 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700690 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
691 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700692 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700693 if (networkProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800694 mRealProviders.add(networkProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000695 addProviderLocked(networkProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800696 networkProviderManager.attachLocked(networkProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700697 } else {
gomo48f1a642017-11-10 20:35:46 -0800698 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700699 }
700
701 // bind to fused provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800702 LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700703 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700704 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700705 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700706 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700707 com.android.internal.R.bool.config_enableFusedLocationOverlay,
708 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700709 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700710 if (fusedProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800711 mRealProviders.add(fusedProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000712 addProviderLocked(fusedProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800713 fusedProviderManager.attachLocked(fusedProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700714 } else {
715 Slog.e(TAG, "no fused location provider found",
716 new IllegalStateException("Location service needs a fused location provider"));
717 }
718
719 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700720 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
721 com.android.internal.R.bool.config_enableGeocoderOverlay,
722 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700723 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700724 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800725 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700726 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700727
destradaaf9a274c2014-07-25 15:11:56 -0700728 // bind to geofence provider
729 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800730 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700731 com.android.internal.R.string.config_geofenceProviderPackageName,
732 com.android.internal.R.array.config_locationProviderPackageNames,
Wei Liu5241a4c2015-05-11 14:00:36 -0700733 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900734 null);
destradaaf9a274c2014-07-25 15:11:56 -0700735 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800736 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700737 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900738
739 String[] testProviderStrings = resources.getStringArray(
740 com.android.internal.R.array.config_testLocationProviders);
741 for (String testProviderString : testProviderStrings) {
742 String fragments[] = testProviderString.split(",");
743 String name = fragments[0].trim();
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900744 ProviderProperties properties = new ProviderProperties(
745 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
746 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
747 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
748 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
749 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
750 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
751 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
752 Integer.parseInt(fragments[8]) /* powerRequirement */,
753 Integer.parseInt(fragments[9]) /* accuracy */);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800754 LocationProvider testProviderManager = new LocationProvider(name);
755 addProviderLocked(testProviderManager);
756 new MockProvider(testProviderManager, properties);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900757 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700758 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700759
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800760 @GuardedBy("mLock")
761 private void onUserChangedLocked(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800762 if (mCurrentUserId == userId) {
763 return;
764 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800765
766 // this call has the side effect of forcing a write to the LOCATION_MODE setting in an OS
767 // upgrade case, and ensures that if anyone checks the LOCATION_MODE setting directly, they
768 // will see it in an appropriate state (at least after that user becomes foreground for the
769 // first time...)
770 isLocationEnabledForUser(userId);
771
772 // let providers know the current user is on the way out before changing the user
773 for (LocationProvider p : mProviders) {
774 p.onUserChangingLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000775 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800776
777 mCurrentUserId = userId;
778 onUserProfilesChangedLocked();
779
780 mBlacklist.switchUser(userId);
781
782 // if the user changes, per-user settings may also have changed
783 onLocationModeChangedLocked(false);
784 onProviderAllowedChangedLocked(false);
Victoria Lease38389b62012-09-30 11:44:22 -0700785 }
786
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800787 private static final class Identity {
788 final int mUid;
789 final int mPid;
790 final String mPackageName;
791
792 Identity(int uid, int pid, String packageName) {
793 mUid = uid;
794 mPid = pid;
795 mPackageName = packageName;
796 }
797 }
798
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700799 private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
800
801 private final String mName;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700802
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800803 // whether this provider should respect LOCATION_PROVIDERS_ALLOWED (ie gps and network)
804 private final boolean mIsManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700805
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800806 // remember to clear binder identity before invoking any provider operation
807 @GuardedBy("mLock")
808 @Nullable protected AbstractLocationProvider mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700809
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800810 @GuardedBy("mLock")
811 private boolean mUseable; // combined state
812 @GuardedBy("mLock")
813 private boolean mAllowed; // state of LOCATION_PROVIDERS_ALLOWED
814 @GuardedBy("mLock")
815 private boolean mEnabled; // state of provider
816
817 @GuardedBy("mLock")
818 @Nullable private ProviderProperties mProperties;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700819
820 private LocationProvider(String name) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800821 this(name, false);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700822 }
823
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800824 private LocationProvider(String name, boolean isManagedBySettings) {
825 mName = name;
826 mIsManagedBySettings = isManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700827
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800828 mProvider = null;
829 mUseable = false;
830 mAllowed = !mIsManagedBySettings;
831 mEnabled = false;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700832 mProperties = null;
Soonil Nagarkar42da1b12019-01-22 11:29:27 -0800833
834 if (mIsManagedBySettings) {
835 // since we assume providers are disabled by default
836 Settings.Secure.putStringForUser(
837 mContext.getContentResolver(),
838 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
839 "-" + mName,
840 mCurrentUserId);
841 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700842 }
843
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800844 @GuardedBy("mLock")
845 public void attachLocked(AbstractLocationProvider provider) {
846 checkNotNull(provider);
847 checkState(mProvider == null);
848 mProvider = provider;
849
850 onUseableChangedLocked();
851 }
852
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700853 public String getName() {
854 return mName;
855 }
856
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800857 @GuardedBy("mLock")
858 @Nullable
859 public String getPackageLocked() {
860 if (mProvider == null) {
861 return null;
862 } else if (mProvider instanceof LocationProviderProxy) {
863 // safe to not clear binder context since this doesn't call into the actual provider
864 return ((LocationProviderProxy) mProvider).getConnectedPackageName();
865 } else {
866 return mContext.getPackageName();
867 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700868 }
869
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800870 public boolean isMock() {
871 return false;
872 }
873
874 @GuardedBy("mLock")
875 public boolean isPassiveLocked() {
876 return mProvider == mPassiveProvider;
877 }
878
879 @GuardedBy("mLock")
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700880 @Nullable
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800881 public ProviderProperties getPropertiesLocked() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700882 return mProperties;
883 }
884
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800885 @GuardedBy("mLock")
886 public void setRequestLocked(ProviderRequest request, WorkSource workSource) {
887 if (mProvider != null) {
888 long identity = Binder.clearCallingIdentity();
889 try {
890 mProvider.setRequest(request, workSource);
891 } finally {
892 Binder.restoreCallingIdentity(identity);
893 }
894 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700895 }
896
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800897 @GuardedBy("mLock")
898 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700899 pw.println(mName + " provider:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800900 if (isMock()) {
901 pw.println(" mock=true");
902 }
903 pw.println(" attached=" + (mProvider != null));
904 if (mIsManagedBySettings) {
905 pw.println(" allowed=" + mAllowed);
906 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700907 pw.println(" enabled=" + mEnabled);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800908 pw.println(" useable=" + mUseable);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700909 pw.println(" properties=" + mProperties);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800910
911 if (mProvider != null) {
912 long identity = Binder.clearCallingIdentity();
913 try {
914 mProvider.dump(fd, pw, args);
915 } finally {
916 Binder.restoreCallingIdentity(identity);
917 }
918 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700919 }
920
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800921 @GuardedBy("mLock")
922 public long getStatusUpdateTimeLocked() {
923 if (mProvider != null) {
924 long identity = Binder.clearCallingIdentity();
925 try {
926 return mProvider.getStatusUpdateTime();
927 } finally {
928 Binder.restoreCallingIdentity(identity);
929 }
930 } else {
931 return 0;
932 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700933 }
934
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800935 @GuardedBy("mLock")
936 public int getStatusLocked(Bundle extras) {
937 if (mProvider != null) {
938 long identity = Binder.clearCallingIdentity();
939 try {
940 return mProvider.getStatus(extras);
941 } finally {
942 Binder.restoreCallingIdentity(identity);
943 }
944 } else {
945 return AVAILABLE;
946 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700947 }
948
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800949 @GuardedBy("mLock")
950 public void sendExtraCommandLocked(String command, Bundle extras) {
951 if (mProvider != null) {
952 long identity = Binder.clearCallingIdentity();
953 try {
954 mProvider.sendExtraCommand(command, extras);
955 } finally {
956 Binder.restoreCallingIdentity(identity);
957 }
958 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700959 }
960
961 // called from any thread
962 @Override
963 public void onReportLocation(Location location) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800964 // no security check necessary because this is coming from an internal-only interface
965 // move calls coming from below LMS onto a different thread to avoid deadlock
966 runInternal(() -> {
967 synchronized (mLock) {
968 handleLocationChangedLocked(location, this);
969 }
970 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700971 }
972
973 // called from any thread
974 @Override
975 public void onReportLocation(List<Location> locations) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800976 // move calls coming from below LMS onto a different thread to avoid deadlock
977 runInternal(() -> {
978 synchronized (mLock) {
979 LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
980 if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
981 Slog.w(TAG, "reportLocationBatch() called without user permission");
982 return;
983 }
984
985 if (mGnssBatchingCallback == null) {
986 Slog.e(TAG, "reportLocationBatch() called without active Callback");
987 return;
988 }
989
990 try {
991 mGnssBatchingCallback.onLocationBatch(locations);
992 } catch (RemoteException e) {
993 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
994 }
995 }
996 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700997 }
998
999 // called from any thread
1000 @Override
1001 public void onSetEnabled(boolean enabled) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001002 // move calls coming from below LMS onto a different thread to avoid deadlock
1003 runInternal(() -> {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001004 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001005 if (enabled == mEnabled) {
1006 return;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001007 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001008
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001009 mEnabled = enabled;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001010
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001011 // update provider allowed settings to reflect enabled status
1012 if (mIsManagedBySettings) {
1013 if (mEnabled && !mAllowed) {
1014 Settings.Secure.putStringForUser(
1015 mContext.getContentResolver(),
1016 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1017 "+" + mName,
1018 mCurrentUserId);
1019 } else if (!mEnabled && mAllowed) {
1020 Settings.Secure.putStringForUser(
1021 mContext.getContentResolver(),
1022 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1023 "-" + mName,
1024 mCurrentUserId);
1025 }
1026 }
1027
1028 onUseableChangedLocked();
1029 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001030 });
1031 }
1032
1033 @Override
1034 public void onSetProperties(ProviderProperties properties) {
Soonil Nagarkar66c0bac2019-01-15 13:36:44 -08001035 // because this does not invoke any other methods which might result in calling back
1036 // into the location provider, it is safe to run this on the calling thread. it is also
1037 // currently necessary to run this on the calling thread to ensure that property changes
1038 // are publicly visibly immediately, ie for mock providers which are created.
1039 synchronized (mLock) {
1040 mProperties = properties;
1041 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001042 }
1043
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001044 @GuardedBy("mLock")
1045 public void onLocationModeChangedLocked() {
1046 onUseableChangedLocked();
1047 }
1048
1049 private boolean isAllowed() {
1050 return isAllowedForUser(mCurrentUserId);
1051 }
1052
1053 private boolean isAllowedForUser(int userId) {
1054 String allowedProviders = Settings.Secure.getStringForUser(
1055 mContext.getContentResolver(),
1056 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1057 userId);
1058 return TextUtils.delimitedStringContains(allowedProviders, ',', mName);
1059 }
1060
1061 @GuardedBy("mLock")
1062 public void onAllowedChangedLocked() {
1063 if (mIsManagedBySettings) {
1064 boolean allowed = isAllowed();
1065 if (allowed == mAllowed) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001066 return;
1067 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001068 mAllowed = allowed;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001069
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001070 // make a best effort to keep the setting matching the real enabled state of the
1071 // provider so that legacy applications aren't broken.
1072 if (mAllowed && !mEnabled) {
1073 Settings.Secure.putStringForUser(
1074 mContext.getContentResolver(),
1075 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1076 "-" + mName,
1077 mCurrentUserId);
1078 }
1079
1080 onUseableChangedLocked();
1081 }
1082 }
1083
1084 @GuardedBy("mLock")
1085 public boolean isUseableLocked() {
1086 return isUseableForUserLocked(mCurrentUserId);
1087 }
1088
1089 @GuardedBy("mLock")
1090 public boolean isUseableForUserLocked(int userId) {
1091 return userId == mCurrentUserId && mUseable;
1092 }
1093
1094 @GuardedBy("mLock")
1095 public void onUseableChangedLocked() {
1096 // if any property that contributes to "useability" here changes state, it MUST result
1097 // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
1098 // guarantee that it will always eventually reach the correct state.
1099 boolean useable = mProvider != null
1100 && mProviders.contains(this) && isLocationEnabled() && mAllowed && mEnabled;
1101 if (useable == mUseable) {
1102 return;
1103 }
1104 mUseable = useable;
1105
1106 if (!mUseable) {
1107 // If any provider has been disabled, clear all last locations for all
1108 // providers. This is to be on the safe side in case a provider has location
1109 // derived from this disabled provider.
1110 mLastLocation.clear();
1111 mLastLocationCoarseInterval.clear();
1112 }
1113
1114 updateProviderUseableLocked(this);
1115 }
1116
1117 @GuardedBy("mLock")
1118 public void onUserChangingLocked() {
1119 // when the user is about to change, we set this provider to un-useable, and notify all
1120 // of the current user clients. when the user is finished changing, useability will be
1121 // updated back via onLocationModeChanged() and onAllowedChanged().
1122 mUseable = false;
1123 updateProviderUseableLocked(this);
1124 }
1125
1126 // binder transactions coming from below LMS (ie location providers) need to be moved onto
1127 // a different thread to avoid potential deadlock as code reenters the location providers
1128 private void runInternal(Runnable runnable) {
1129 if (Looper.myLooper() == mHandler.getLooper()) {
1130 runnable.run();
1131 } else {
1132 mHandler.post(runnable);
1133 }
1134 }
1135 }
1136
1137 private class MockLocationProvider extends LocationProvider {
1138
1139 private MockLocationProvider(String name) {
1140 super(name);
1141 }
1142
1143 @Override
1144 public void attachLocked(AbstractLocationProvider provider) {
1145 checkState(provider instanceof MockProvider);
1146 super.attachLocked(provider);
1147 }
1148
1149 public boolean isMock() {
1150 return true;
1151 }
1152
1153 @GuardedBy("mLock")
1154 public void setEnabledLocked(boolean enabled) {
1155 if (mProvider != null) {
1156 long identity = Binder.clearCallingIdentity();
1157 try {
1158 ((MockProvider) mProvider).setEnabled(enabled);
1159 } finally {
1160 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00001161 }
1162 }
1163 }
1164
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001165 @GuardedBy("mLock")
1166 public void setLocationLocked(Location location) {
1167 if (mProvider != null) {
1168 long identity = Binder.clearCallingIdentity();
1169 try {
1170 ((MockProvider) mProvider).setLocation(location);
1171 } finally {
1172 Binder.restoreCallingIdentity(identity);
1173 }
1174 }
1175 }
1176
1177 @GuardedBy("mLock")
1178 public void setStatusLocked(int status, Bundle extras, long updateTime) {
1179 if (mProvider != null) {
1180 long identity = Binder.clearCallingIdentity();
1181 try {
1182 ((MockProvider) mProvider).setStatus(status, extras, updateTime);
1183 } finally {
1184 Binder.restoreCallingIdentity(identity);
1185 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001186 }
1187 }
1188 }
1189
Victoria Lease38389b62012-09-30 11:44:22 -07001190 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
1192 * location updates.
1193 */
Mike Lockwood48f17512009-04-23 09:12:08 -07001194 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -07001195 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001196 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001197 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001198
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001199 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -07001201 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001202 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
1203 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001204
gomo48f1a642017-11-10 20:35:46 -08001205 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -07001206
David Christie0b837452013-07-29 16:02:13 -07001207 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001208 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -07001209 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001210 private boolean mOpHighPowerMonitoring;
1211 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -07001212 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001214 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001215 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001218 if (listener != null) {
1219 mKey = listener.asBinder();
1220 } else {
1221 mKey = intent;
1222 }
Victoria Lease37425c32012-10-16 16:08:48 -07001223 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001224 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +00001225 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -07001226 workSource = null;
1227 }
1228 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -07001229 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -07001230
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001231 updateMonitoring(true);
1232
Victoria Lease0aa28602013-05-29 15:28:26 -07001233 // construct/configure wakelock
1234 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -07001235 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001236 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001237 }
1238 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -07001239
1240 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
1241 // only need to release it once.
1242 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 }
1244
1245 @Override
1246 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001247 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 }
1249
1250 @Override
1251 public int hashCode() {
1252 return mKey.hashCode();
1253 }
Mike Lockwood3681f262009-05-12 10:52:03 -04001254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 @Override
1256 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001257 StringBuilder s = new StringBuilder();
1258 s.append("Reciever[");
1259 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001261 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001263 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001265 for (String p : mUpdateRecords.keySet()) {
1266 s.append(" ").append(mUpdateRecords.get(p).toString());
1267 }
Wei Wangdd070f22018-06-21 11:29:40 -07001268 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001269 s.append("]");
1270 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 }
1272
David Christie15b31912013-08-13 15:54:32 -07001273 /**
1274 * Update AppOp monitoring for this receiver.
1275 *
1276 * @param allow If true receiver is currently active, if false it's been removed.
1277 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001278 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001279 if (mHideFromAppOps) {
1280 return;
1281 }
1282
David Christie15b31912013-08-13 15:54:32 -07001283 boolean requestingLocation = false;
1284 boolean requestingHighPowerLocation = false;
1285 if (allow) {
1286 // See if receiver has any enabled update records. Also note if any update records
1287 // are high power (has a high power provider with an interval under a threshold).
1288 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001289 LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
1290 if (provider == null || !provider.isUseableLocked()) {
1291 continue;
1292 }
1293
1294 requestingLocation = true;
1295 ProviderProperties properties = provider.getPropertiesLocked();
1296 if (properties != null
1297 && properties.mPowerRequirement == Criteria.POWER_HIGH
1298 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1299 requestingHighPowerLocation = true;
1300 break;
David Christie15b31912013-08-13 15:54:32 -07001301 }
1302 }
1303 }
1304
David Christie0b837452013-07-29 16:02:13 -07001305 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001306 mOpMonitoring = updateMonitoring(
1307 requestingLocation,
1308 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001309 AppOpsManager.OP_MONITOR_LOCATION);
1310
1311 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001312 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001313 mOpHighPowerMonitoring = updateMonitoring(
1314 requestingHighPowerLocation,
1315 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001316 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001317 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001318 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001319 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1320 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1321 }
David Christie0b837452013-07-29 16:02:13 -07001322 }
1323
1324 /**
1325 * Update AppOps monitoring for a single location request and op type.
1326 *
gomo48f1a642017-11-10 20:35:46 -08001327 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001328 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001329 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001330 * @return True if monitoring is on for this request/op after updating.
1331 */
1332 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1333 int op) {
1334 if (!currentlyMonitoring) {
1335 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001336 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001337 == AppOpsManager.MODE_ALLOWED;
1338 }
1339 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001340 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001341 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001342 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001343 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001344 return false;
1345 }
1346 }
1347
1348 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001349 }
1350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 public boolean isListener() {
1352 return mListener != null;
1353 }
1354
1355 public boolean isPendingIntent() {
1356 return mPendingIntent != null;
1357 }
1358
1359 public ILocationListener getListener() {
1360 if (mListener != null) {
1361 return mListener;
1362 }
1363 throw new IllegalStateException("Request for non-existent listener");
1364 }
1365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1367 if (mListener != null) {
1368 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001369 synchronized (this) {
1370 // synchronize to ensure incrementPendingBroadcastsLocked()
1371 // is called before decrementPendingBroadcasts()
1372 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001373 // call this after broadcasting so we do not increment
1374 // if we throw an exeption.
1375 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001376 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 } catch (RemoteException e) {
1378 return false;
1379 }
1380 } else {
1381 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001382 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1384 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001385 synchronized (this) {
1386 // synchronize to ensure incrementPendingBroadcastsLocked()
1387 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001388 mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001389 getResolutionPermission(mAllowedResolutionLevel),
1390 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001391 // call this after broadcasting so we do not increment
1392 // if we throw an exeption.
1393 incrementPendingBroadcastsLocked();
1394 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 } catch (PendingIntent.CanceledException e) {
1396 return false;
1397 }
1398 }
1399 return true;
1400 }
1401
1402 public boolean callLocationChangedLocked(Location location) {
1403 if (mListener != null) {
1404 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001405 synchronized (this) {
1406 // synchronize to ensure incrementPendingBroadcastsLocked()
1407 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001408 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001409 // call this after broadcasting so we do not increment
1410 // if we throw an exeption.
1411 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001412 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 } catch (RemoteException e) {
1414 return false;
1415 }
1416 } else {
1417 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001418 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1419 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001421 synchronized (this) {
1422 // synchronize to ensure incrementPendingBroadcastsLocked()
1423 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001424 mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001425 getResolutionPermission(mAllowedResolutionLevel),
1426 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001427 // call this after broadcasting so we do not increment
1428 // if we throw an exeption.
1429 incrementPendingBroadcastsLocked();
1430 }
1431 } catch (PendingIntent.CanceledException e) {
1432 return false;
1433 }
1434 }
1435 return true;
1436 }
1437
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001438 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001439 // First update AppOp monitoring.
1440 // An app may get/lose location access as providers are enabled/disabled.
1441 updateMonitoring(true);
1442
Mike Lockwood48f17512009-04-23 09:12:08 -07001443 if (mListener != null) {
1444 try {
1445 synchronized (this) {
1446 // synchronize to ensure incrementPendingBroadcastsLocked()
1447 // is called before decrementPendingBroadcasts()
1448 if (enabled) {
1449 mListener.onProviderEnabled(provider);
1450 } else {
1451 mListener.onProviderDisabled(provider);
1452 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001453 // call this after broadcasting so we do not increment
1454 // if we throw an exeption.
1455 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001456 }
1457 } catch (RemoteException e) {
1458 return false;
1459 }
1460 } else {
1461 Intent providerIntent = new Intent();
1462 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1463 try {
1464 synchronized (this) {
1465 // synchronize to ensure incrementPendingBroadcastsLocked()
1466 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001467 mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001468 getResolutionPermission(mAllowedResolutionLevel),
1469 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001470 // call this after broadcasting so we do not increment
1471 // if we throw an exeption.
1472 incrementPendingBroadcastsLocked();
1473 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 } catch (PendingIntent.CanceledException e) {
1475 return false;
1476 }
1477 }
1478 return true;
1479 }
1480
Nick Pellyf1be6862012-05-15 10:53:42 -07001481 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001483 if (D) Log.d(TAG, "Location listener died");
1484
Soonil Nagarkar68257742019-01-09 19:42:34 +00001485 synchronized (mLock) {
1486 removeUpdatesLocked(this);
1487 }
1488 synchronized (this) {
1489 clearPendingBroadcastsLocked();
1490 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001491 }
1492
Nick Pellye0fd6932012-07-11 10:26:13 -07001493 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001494 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1495 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001496 synchronized (this) {
1497 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001498 }
1499 }
1500
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001501 // this must be called while synchronized by caller in a synchronized block
1502 // containing the sending of the broadcaset
1503 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001504 mPendingBroadcasts++;
1505 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001506 }
1507
1508 private void decrementPendingBroadcastsLocked() {
1509 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001510 if (mWakeLock.isHeld()) {
1511 mWakeLock.release();
1512 }
1513 }
1514 }
1515
1516 public void clearPendingBroadcastsLocked() {
1517 if (mPendingBroadcasts > 0) {
1518 mPendingBroadcasts = 0;
1519 if (mWakeLock.isHeld()) {
1520 mWakeLock.release();
1521 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001522 }
1523 }
1524 }
1525
Nick Pellye0fd6932012-07-11 10:26:13 -07001526 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001527 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001528 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001529 //the receiver list if it is not found. If it is not found then the
1530 //LocationListener was removed when it had a pending broadcast and should
1531 //not be added back.
Soonil Nagarkar68257742019-01-09 19:42:34 +00001532 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001533 IBinder binder = listener.asBinder();
1534 Receiver receiver = mReceivers.get(binder);
1535 if (receiver != null) {
1536 synchronized (receiver) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001537 // so wakelock calls will succeed
1538 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001539 try {
1540 receiver.decrementPendingBroadcastsLocked();
1541 } finally {
1542 Binder.restoreCallingIdentity(identity);
1543 }
David Christie2ff96af2014-01-30 16:09:37 -08001544 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001545 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 }
1548
Lifu Tang82f893d2016-01-21 18:15:33 -08001549 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001550 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001551 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001552 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001553 } else {
1554 return 0;
1555 }
1556 }
1557
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001558 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001559 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001560 public String getGnssHardwareModelName() {
1561 if (mGnssSystemInfoProvider != null) {
1562 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1563 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001564 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001565 }
1566 }
1567
Wyatt Rileycf879db2017-01-12 13:57:38 -08001568 private boolean hasGnssPermissions(String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001569 synchronized (mLock) {
1570 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1571 checkResolutionLevelIsSufficientForProviderUseLocked(
1572 allowedResolutionLevel,
1573 GPS_PROVIDER);
Wyatt Rileycf879db2017-01-12 13:57:38 -08001574
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001575 int pid = Binder.getCallingPid();
1576 int uid = Binder.getCallingUid();
1577 long identity = Binder.clearCallingIdentity();
1578 try {
1579 return checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1580 } finally {
1581 Binder.restoreCallingIdentity(identity);
1582 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001583 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001584 }
1585
Wyatt Rileycf879db2017-01-12 13:57:38 -08001586 @Override
1587 public int getGnssBatchSize(String packageName) {
1588 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1589 "Location Hardware permission not granted to access hardware batching");
1590
1591 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001592 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001593 } else {
1594 return 0;
1595 }
1596 }
1597
Wyatt Rileycf879db2017-01-12 13:57:38 -08001598 @Override
1599 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1600 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1601 "Location Hardware permission not granted to access hardware batching");
1602
1603 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1604 return false;
1605 }
1606
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001607 synchronized (mLock) {
1608 mGnssBatchingCallback = callback;
1609 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1610 try {
1611 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1612 } catch (RemoteException e) {
1613 // if the remote process registering the listener is already dead, just swallow the
1614 // exception and return
1615 Log.e(TAG, "Remote listener already died.", e);
1616 return false;
1617 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001618
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001619 return true;
1620 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001621 }
1622
1623 private class LinkedCallback implements IBinder.DeathRecipient {
1624 private final IBatchedLocationCallback mCallback;
1625
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001626 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001627 mCallback = callback;
1628 }
1629
1630 @NonNull
1631 public IBatchedLocationCallback getUnderlyingListener() {
1632 return mCallback;
1633 }
1634
1635 @Override
1636 public void binderDied() {
1637 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1638 stopGnssBatch();
1639 removeGnssBatchingCallback();
1640 }
1641 }
1642
Wyatt Rileycf879db2017-01-12 13:57:38 -08001643 @Override
1644 public void removeGnssBatchingCallback() {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001645 synchronized (mLock) {
1646 try {
1647 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1648 0 /* flags */);
1649 } catch (NoSuchElementException e) {
1650 // if the death callback isn't connected (it should be...), log error, swallow the
1651 // exception and return
1652 Log.e(TAG, "Couldn't unlink death callback.", e);
1653 }
1654 mGnssBatchingCallback = null;
1655 mGnssBatchingDeathCallback = null;
Wyatt Rileycf879db2017-01-12 13:57:38 -08001656 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001657 }
1658
Wyatt Rileycf879db2017-01-12 13:57:38 -08001659 @Override
1660 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1661 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1662 "Location Hardware permission not granted to access hardware batching");
1663
1664 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1665 return false;
1666 }
1667
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001668 synchronized (mLock) {
1669 if (mGnssBatchingInProgress) {
1670 // Current design does not expect multiple starts to be called repeatedly
1671 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1672 // Try to clean up anyway, and continue
1673 stopGnssBatch();
1674 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001675
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001676 mGnssBatchingInProgress = true;
1677 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1678 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001679 }
1680
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001681
Wyatt Rileycf879db2017-01-12 13:57:38 -08001682 @Override
1683 public void flushGnssBatch(String packageName) {
1684 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1685 "Location Hardware permission not granted to access hardware batching");
1686
1687 if (!hasGnssPermissions(packageName)) {
1688 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1689 return;
1690 }
1691
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001692 synchronized (mLock) {
1693 if (!mGnssBatchingInProgress) {
1694 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1695 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001696
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001697 if (mGnssBatchingProvider != null) {
1698 mGnssBatchingProvider.flush();
1699 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001700 }
1701 }
1702
Wyatt Rileycf879db2017-01-12 13:57:38 -08001703 @Override
1704 public boolean stopGnssBatch() {
1705 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1706 "Location Hardware permission not granted to access hardware batching");
1707
Soonil Nagarkar68257742019-01-09 19:42:34 +00001708 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001709 if (mGnssBatchingProvider != null) {
1710 mGnssBatchingInProgress = false;
1711 return mGnssBatchingProvider.stop();
1712 } else {
1713 return false;
1714 }
1715 }
1716 }
1717
1718 @GuardedBy("mLock")
1719 private void addProviderLocked(LocationProvider provider) {
1720 Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
1721
1722 mProviders.add(provider);
1723
1724 provider.onAllowedChangedLocked(); // allowed state may change while provider was inactive
1725 provider.onUseableChangedLocked();
1726 }
1727
1728 @GuardedBy("mLock")
1729 private void removeProviderLocked(LocationProvider provider) {
1730 if (mProviders.remove(provider)) {
1731 long identity = Binder.clearCallingIdentity();
1732 try {
1733 provider.onUseableChangedLocked();
1734 } finally {
1735 Binder.restoreCallingIdentity(identity);
1736 }
1737 }
1738 }
1739
1740 @GuardedBy("mLock")
1741 @Nullable
1742 private LocationProvider getLocationProviderLocked(String providerName) {
1743 for (LocationProvider provider : mProviders) {
1744 if (providerName.equals(provider.getName())) {
1745 return provider;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001746 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001747 }
1748
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001749 return null;
Maggie2a9409e2018-03-21 11:47:28 -07001750 }
1751
Victoria Lease37425c32012-10-16 16:08:48 -07001752 private String getResolutionPermission(int resolutionLevel) {
1753 switch (resolutionLevel) {
1754 case RESOLUTION_LEVEL_FINE:
1755 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1756 case RESOLUTION_LEVEL_COARSE:
1757 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1758 default:
1759 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001761 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001762
Victoria Lease37425c32012-10-16 16:08:48 -07001763 private int getAllowedResolutionLevel(int pid, int uid) {
1764 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001765 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001766 return RESOLUTION_LEVEL_FINE;
1767 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001768 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001769 return RESOLUTION_LEVEL_COARSE;
1770 } else {
1771 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001772 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001773 }
1774
Victoria Lease37425c32012-10-16 16:08:48 -07001775 private int getCallerAllowedResolutionLevel() {
1776 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1777 }
1778
Victoria Lease37425c32012-10-16 16:08:48 -07001779 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1780 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001781 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 }
1784
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001785 @GuardedBy("mLock")
1786 private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
1787 if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001788 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001789 return RESOLUTION_LEVEL_FINE;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001790 } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001791 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001792 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001793 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001794 for (LocationProvider lp : mProviders) {
1795 if (!lp.getName().equals(provider)) {
1796 continue;
1797 }
1798
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001799 ProviderProperties properties = lp.getPropertiesLocked();
Laurent Tu941221c2012-10-04 14:21:52 -07001800 if (properties != null) {
1801 if (properties.mRequiresSatellite) {
1802 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001803 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001804 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1805 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001806 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001807 }
1808 }
1809 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001810 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001811
Victoria Lease37425c32012-10-16 16:08:48 -07001812 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001813 }
1814
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001815 @GuardedBy("mLock")
1816 private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001817 String providerName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001818 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
Victoria Lease37425c32012-10-16 16:08:48 -07001819 if (allowedResolutionLevel < requiredResolutionLevel) {
1820 switch (requiredResolutionLevel) {
1821 case RESOLUTION_LEVEL_FINE:
1822 throw new SecurityException("\"" + providerName + "\" location provider " +
1823 "requires ACCESS_FINE_LOCATION permission.");
1824 case RESOLUTION_LEVEL_COARSE:
1825 throw new SecurityException("\"" + providerName + "\" location provider " +
1826 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1827 default:
1828 throw new SecurityException("Insufficient permission for \"" + providerName +
1829 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001830 }
1831 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001832 }
1833
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001834 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001835 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1836 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001837 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001838 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001839 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001840 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001841 }
1842 return -1;
1843 }
1844
Wei Wangb86334f2018-07-03 16:33:24 -07001845 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001846 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001847 case RESOLUTION_LEVEL_COARSE:
1848 return AppOpsManager.OPSTR_COARSE_LOCATION;
1849 case RESOLUTION_LEVEL_FINE:
1850 return AppOpsManager.OPSTR_FINE_LOCATION;
1851 case RESOLUTION_LEVEL_NONE:
1852 // The client is not allowed to get any location, so both FINE and COARSE ops will
1853 // be denied. Pick the most restrictive one to be safe.
1854 return AppOpsManager.OPSTR_FINE_LOCATION;
1855 default:
1856 // Use the most restrictive ops if not sure.
1857 return AppOpsManager.OPSTR_FINE_LOCATION;
1858 }
1859 }
1860
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001861 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001862 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001863 int op = resolutionLevelToOp(allowedResolutionLevel);
1864 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001865 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1866 return false;
1867 }
1868 }
David Christieb870dbf2015-06-22 12:42:53 -07001869
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001870 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001871 }
1872
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001873 private boolean checkLocationAccess(int pid, int uid, String packageName,
1874 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001875 int op = resolutionLevelToOp(allowedResolutionLevel);
1876 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001877 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001878 return false;
1879 }
1880 }
David Christieb870dbf2015-06-22 12:42:53 -07001881
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001882 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001883 }
1884
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001885 /**
Maggie91e630c2018-01-24 17:31:46 -08001886 * Returns all providers by name, including passive and the ones that are not permitted to
1887 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001888 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001889 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 public List<String> getAllProviders() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001891 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001892 ArrayList<String> providers = new ArrayList<>(mProviders.size());
Soonil Nagarkar68257742019-01-09 19:42:34 +00001893 for (LocationProvider provider : mProviders) {
1894 String name = provider.getName();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001895 if (FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001896 continue;
1897 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001898 providers.add(name);
Maggie91e630c2018-01-24 17:31:46 -08001899 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001900 return providers;
Maggie91e630c2018-01-24 17:31:46 -08001901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 }
1903
Mike Lockwood03ca2162010-04-01 08:10:09 -07001904 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001905 * Return all providers by name, that match criteria and are optionally
1906 * enabled.
1907 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001908 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001909 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001910 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001911 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001912 synchronized (mLock) {
1913 ArrayList<String> providers = new ArrayList<>(mProviders.size());
1914 for (LocationProvider provider : mProviders) {
1915 String name = provider.getName();
1916 if (FUSED_PROVIDER.equals(name)) {
1917 continue;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001918 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001919 if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
1920 continue;
1921 }
1922 if (enabledOnly && !provider.isUseableLocked()) {
1923 continue;
1924 }
1925 if (criteria != null
1926 && !android.location.LocationProvider.propertiesMeetCriteria(
1927 name, provider.getPropertiesLocked(), criteria)) {
1928 continue;
1929 }
1930 providers.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001931 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001932 return providers;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001933 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001934 }
1935
1936 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001937 * Return the name of the best provider given a Criteria object.
1938 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001939 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001940 * has been deprecated as well. So this method now uses
1941 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001942 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001943 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001944 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001945 List<String> providers = getProviders(criteria, enabledOnly);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001946 if (providers.isEmpty()) {
1947 providers = getProviders(null, enabledOnly);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001948 }
1949
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001950 if (!providers.isEmpty()) {
1951 if (providers.contains(GPS_PROVIDER)) {
1952 return GPS_PROVIDER;
1953 } else if (providers.contains(NETWORK_PROVIDER)) {
1954 return NETWORK_PROVIDER;
1955 } else {
1956 return providers.get(0);
1957 }
1958 }
1959
Mike Lockwood03ca2162010-04-01 08:10:09 -07001960 return null;
1961 }
1962
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001963 @GuardedBy("mLock")
1964 private void updateProviderUseableLocked(LocationProvider provider) {
1965 boolean useable = provider.isUseableLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001968
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001969 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001971 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001972 if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001973 // Sends a notification message to the receiver
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001974 if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001975 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001976 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001977 }
1978 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 }
1982 }
1983
1984 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001985 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001986 removeUpdatesLocked(deadReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 }
1988 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001989
Soonil Nagarkar68257742019-01-09 19:42:34 +00001990 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 }
1992
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001993 @GuardedBy("mLock")
1994 private void applyRequirementsLocked(String providerName) {
1995 LocationProvider provider = getLocationProviderLocked(providerName);
1996 if (provider != null) {
1997 applyRequirementsLocked(provider);
1998 }
1999 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002000
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002001 @GuardedBy("mLock")
2002 private void applyRequirementsLocked(LocationProvider provider) {
2003 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002004 WorkSource worksource = new WorkSource();
2005 ProviderRequest providerRequest = new ProviderRequest();
2006
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002007 long backgroundThrottleInterval;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002008
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002009 long identity = Binder.clearCallingIdentity();
2010 try {
2011 backgroundThrottleInterval = Settings.Global.getLong(
2012 mContext.getContentResolver(),
2013 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
2014 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
2015 } finally {
2016 Binder.restoreCallingIdentity(identity);
2017 }
2018
2019 if (provider.isUseableLocked() && records != null && !records.isEmpty()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002020 // initialize the low power mode to true and set to false if any of the records requires
2021 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002022 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002023 if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07002024 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002025 record.mReceiver.mIdentity.mPid,
2026 record.mReceiver.mIdentity.mUid,
2027 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002028 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002029 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002030 long interval = locationRequest.getInterval();
2031
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002032 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002033 if (!record.mIsForegroundUid) {
2034 interval = Math.max(interval, backgroundThrottleInterval);
2035 }
2036 if (interval != locationRequest.getInterval()) {
2037 locationRequest = new LocationRequest(locationRequest);
2038 locationRequest.setInterval(interval);
2039 }
2040 }
2041
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002042 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002043 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08002044 if (!locationRequest.isLowPowerMode()) {
2045 providerRequest.lowPowerMode = false;
2046 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002047 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002048 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002049 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002050 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002051 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002052 }
2053 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002054
2055 if (providerRequest.reportLocation) {
2056 // calculate who to blame for power
2057 // This is somewhat arbitrary. We pick a threshold interval
2058 // that is slightly higher that the minimum interval, and
2059 // spread the blame across all applications with a request
2060 // under that threshold.
2061 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
2062 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002063 if (isCurrentProfileLocked(
2064 UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002065 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07002066
2067 // Don't assign battery blame for update records whose
2068 // client has no permission to receive location data.
2069 if (!providerRequest.locationRequests.contains(locationRequest)) {
2070 continue;
2071 }
2072
Victoria Leaseb711d572012-10-02 13:14:11 -07002073 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07002074 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00002075 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07002076 worksource.add(record.mReceiver.mWorkSource);
2077 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00002078 // Assign blame to caller if there's no WorkSource associated with
2079 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07002080 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002081 record.mReceiver.mIdentity.mUid,
2082 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07002083 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002084 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002085 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 }
2088 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002089
2090 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002091 provider.setRequestLocked(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002092 }
2093
Narayan Kamath32684dd2018-01-08 17:32:51 +00002094 /**
2095 * Whether a given {@code WorkSource} associated with a Location request is valid.
2096 */
2097 private static boolean isValidWorkSource(WorkSource workSource) {
2098 if (workSource.size() > 0) {
2099 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
2100 // by tags.
2101 return workSource.getName(0) != null;
2102 } else {
2103 // For now, make sure callers have supplied an attribution tag for use with
2104 // AppOpsManager. This might be relaxed in the future.
2105 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
2106 return workChains != null && !workChains.isEmpty() &&
2107 workChains.get(0).getAttributionTag() != null;
2108 }
2109 }
2110
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002111 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002112 public String[] getBackgroundThrottlingWhitelist() {
2113 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002114 return mBackgroundThrottlePackageWhitelist.toArray(new String[0]);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002115 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002116 }
2117
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002118 @GuardedBy("mLock")
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002119 private boolean isThrottlingExemptLocked(Identity identity) {
2120 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002121 return true;
2122 }
2123
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002124 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002125 return true;
2126 }
2127
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002128 for (LocationProvider provider : mProviders) {
2129 if (identity.mPackageName.equals(provider.getPackageLocked())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002130 return true;
2131 }
2132 }
2133
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002134 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002135 }
2136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 private class UpdateRecord {
2138 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002139 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002140 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002141 private final Receiver mReceiver;
2142 private boolean mIsForegroundUid;
2143 private Location mLastFixBroadcast;
2144 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145
2146 /**
2147 * Note: must be constructed with lock held.
2148 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002149 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002150 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002151 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002152 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002153 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002154 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002155 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156
2157 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2158 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002159 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 mRecordsByProvider.put(provider, records);
2161 }
2162 if (!records.contains(this)) {
2163 records.add(this);
2164 }
David Christie2ff96af2014-01-30 16:09:37 -08002165
2166 // Update statistics for historical location requests by package/provider
2167 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002168 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2169 mIsForegroundUid);
2170 }
2171
2172 /**
2173 * Method to be called when record changes foreground/background
2174 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002175 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002176 mIsForegroundUid = isForeground;
2177 mRequestStatistics.updateForeground(
2178 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 }
2180
2181 /**
David Christie2ff96af2014-01-30 16:09:37 -08002182 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002184 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002185 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002186
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002187 // remove from mRecordsByProvider
2188 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2189 if (globalRecords != null) {
2190 globalRecords.remove(this);
2191 }
2192
2193 if (!removeReceiver) return; // the caller will handle the rest
2194
2195 // remove from Receiver#mUpdateRecords
2196 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002197 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002198
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002199 // and also remove the Receiver if it has no more update records
2200 if (receiverRecords.size() == 0) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002201 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 }
2204
2205 @Override
2206 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002207 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002208 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2209 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002210 + ")" + " " + mRealRequest + " "
2211 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 }
2214
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002215 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002216 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002217 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002218 IBinder binder = listener.asBinder();
2219 Receiver receiver = mReceivers.get(binder);
2220 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002221 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2222 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002223 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002224 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002225 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002226 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002227 return null;
2228 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002229 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002230 }
2231 return receiver;
2232 }
2233
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002234 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002235 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002236 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002237 Receiver receiver = mReceivers.get(intent);
2238 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002239 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2240 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002241 mReceivers.put(intent, receiver);
2242 }
2243 return receiver;
2244 }
2245
Victoria Lease37425c32012-10-16 16:08:48 -07002246 /**
2247 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2248 * and consistency requirements.
2249 *
2250 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002251 * @return a version of request that meets the given resolution and consistency requirements
2252 * @hide
2253 */
gomo48f1a642017-11-10 20:35:46 -08002254 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2255 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002256 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002257 if (!callerHasLocationHardwarePermission) {
2258 // allow setting low power mode only for callers with location hardware permission
2259 sanitizedRequest.setLowPowerMode(false);
2260 }
Victoria Lease37425c32012-10-16 16:08:48 -07002261 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2262 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002263 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002264 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002265 break;
2266 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002267 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002268 break;
2269 }
2270 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002271 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2272 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002273 }
Victoria Lease37425c32012-10-16 16:08:48 -07002274 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2275 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002276 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002277 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002278 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002279 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002280 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002281 }
Victoria Lease37425c32012-10-16 16:08:48 -07002282 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002283 }
2284
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002285 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002286 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002287 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002288 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002289 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002290 String[] packages = mPackageManager.getPackagesForUid(uid);
2291 if (packages == null) {
2292 throw new SecurityException("invalid UID " + uid);
2293 }
2294 for (String pkg : packages) {
2295 if (packageName.equals(pkg)) return;
2296 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002297 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002298 }
2299
Nick Pellye0fd6932012-07-11 10:26:13 -07002300 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002301 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002302 PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002303 synchronized (mLock) {
2304 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2305 checkPackageName(packageName);
2306 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2307 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2308 request.getProvider());
2309 WorkSource workSource = request.getWorkSource();
2310 if (workSource != null && !workSource.isEmpty()) {
2311 mContext.enforceCallingOrSelfPermission(
2312 Manifest.permission.UPDATE_DEVICE_STATS, null);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002313 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002314 boolean hideFromAppOps = request.getHideFromAppOps();
2315 if (hideFromAppOps) {
2316 mContext.enforceCallingOrSelfPermission(
2317 Manifest.permission.UPDATE_APP_OPS_STATS, null);
2318 }
2319 boolean callerHasLocationHardwarePermission =
2320 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2321 == PERMISSION_GRANTED;
2322 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2323 allowedResolutionLevel,
2324 callerHasLocationHardwarePermission);
2325
2326 final int pid = Binder.getCallingPid();
2327 final int uid = Binder.getCallingUid();
2328
2329 long identity = Binder.clearCallingIdentity();
2330 try {
2331
2332 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2333 // a location.
2334 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
2335
2336 if (intent == null && listener == null) {
2337 throw new IllegalArgumentException("need either listener or intent");
2338 } else if (intent != null && listener != null) {
2339 throw new IllegalArgumentException(
2340 "cannot register both listener and intent");
2341 }
2342
2343 Receiver receiver;
2344 if (intent != null) {
2345 receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
2346 hideFromAppOps);
2347 } else {
2348 receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
2349 hideFromAppOps);
2350 }
2351 requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
2352 } finally {
2353 Binder.restoreCallingIdentity(identity);
2354 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002355 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002356 }
2357
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002358 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002359 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002360 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002361 // Figure out the provider. Either its explicitly request (legacy use cases), or
2362 // use the fused provider
2363 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2364 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002365 if (name == null) {
2366 throw new IllegalArgumentException("provider name must not be null");
2367 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002368
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002369 LocationProvider provider = getLocationProviderLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002370 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002371 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002372 }
2373
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002374 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002375 if (D) {
2376 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2377 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2378 + (record.mIsForegroundUid ? "foreground" : "background")
2379 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002380 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002381 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002382
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002383 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2384 if (oldRecord != null) {
2385 oldRecord.disposeLocked(false);
2386 }
2387
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002388 if (provider.isUseableLocked()) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002389 applyRequirementsLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002390 } else {
2391 // Notify the listener that updates are currently disabled
2392 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002393 }
David Christie0b837452013-07-29 16:02:13 -07002394 // Update the monitoring here just in case multiple location requests were added to the
2395 // same receiver (this request may be high power and the initial might not have been).
2396 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002397 }
2398
Nick Pellye0fd6932012-07-11 10:26:13 -07002399 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002400 public void removeUpdates(ILocationListener listener, PendingIntent intent,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002401 String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002402 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002403
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002404 int pid = Binder.getCallingPid();
2405 int uid = Binder.getCallingUid();
2406
2407 if (intent == null && listener == null) {
2408 throw new IllegalArgumentException("need either listener or intent");
2409 } else if (intent != null && listener != null) {
2410 throw new IllegalArgumentException("cannot register both listener and intent");
2411 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002412
Soonil Nagarkar68257742019-01-09 19:42:34 +00002413 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002414 Receiver receiver;
2415 if (intent != null) {
2416 receiver = getReceiverLocked(intent, pid, uid, packageName, null, false);
2417 } else {
2418 receiver = getReceiverLocked(listener, pid, uid, packageName, null, false);
2419 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002420
Soonil Nagarkar68257742019-01-09 19:42:34 +00002421 long identity = Binder.clearCallingIdentity();
2422 try {
2423 removeUpdatesLocked(receiver);
2424 } finally {
2425 Binder.restoreCallingIdentity(identity);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002426 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002428 }
2429
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002430 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002431 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002432 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002433
2434 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2435 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2436 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002437 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002438 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002439 }
2440
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002441 receiver.updateMonitoring(false);
2442
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002443 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002444 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002445 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2446 if (oldRecords != null) {
2447 // Call dispose() on the obsolete update records.
2448 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002449 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002450 record.disposeLocked(false);
2451 }
2452 // Accumulate providers
2453 providers.addAll(oldRecords.keySet());
2454 }
2455
2456 // update provider
2457 for (String provider : providers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002458 applyRequirementsLocked(provider);
2459 }
2460 }
2461
Nick Pellye0fd6932012-07-11 10:26:13 -07002462 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002463 public Location getLastLocation(LocationRequest r, String packageName) {
2464 if (D) Log.d(TAG, "getLastLocation: " + r);
2465 synchronized (mLock) {
2466 LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
2467 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2468 checkPackageName(packageName);
2469 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2470 request.getProvider());
2471 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002472
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002473 final int pid = Binder.getCallingPid();
2474 final int uid = Binder.getCallingUid();
2475 final long identity = Binder.clearCallingIdentity();
2476 try {
2477 if (mBlacklist.isBlacklisted(packageName)) {
2478 if (D) {
2479 Log.d(TAG, "not returning last loc for blacklisted app: "
2480 + packageName);
2481 }
2482 return null;
gomo48f1a642017-11-10 20:35:46 -08002483 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002484
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002485 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
2486 if (D) {
2487 Log.d(TAG, "not returning last loc for no op app: "
2488 + packageName);
2489 }
2490 return null;
gomo48f1a642017-11-10 20:35:46 -08002491 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002492
Soonil Nagarkar68257742019-01-09 19:42:34 +00002493 // Figure out the provider. Either its explicitly request (deprecated API's),
2494 // or use the fused provider
2495 String name = request.getProvider();
2496 if (name == null) name = LocationManager.FUSED_PROVIDER;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002497 LocationProvider provider = getLocationProviderLocked(name);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002498 if (provider == null) return null;
2499
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002500 // only the current user or location providers may get location this way
2501 if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isLocationProviderLocked(
2502 uid)) {
2503 return null;
2504 }
2505
2506 if (!provider.isUseableLocked()) {
2507 return null;
2508 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002509
2510 Location location;
2511 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2512 // Make sure that an app with coarse permissions can't get frequent location
2513 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2514 location = mLastLocationCoarseInterval.get(name);
2515 } else {
2516 location = mLastLocation.get(name);
2517 }
2518 if (location == null) {
2519 return null;
2520 }
2521
2522 // Don't return stale location to apps with foreground-only location permission.
2523 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002524 long locationAgeMs = SystemClock.elapsedRealtime()
2525 - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2526 if ((locationAgeMs > Settings.Global.getLong(
2527 mContext.getContentResolver(),
2528 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2529 DEFAULT_LAST_LOCATION_MAX_AGE_MS))
Soonil Nagarkar68257742019-01-09 19:42:34 +00002530 && (mAppOps.unsafeCheckOp(op, uid, packageName)
2531 == AppOpsManager.MODE_FOREGROUND)) {
2532 return null;
2533 }
2534
2535 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2536 Location noGPSLocation = location.getExtraLocation(
2537 Location.EXTRA_NO_GPS_LOCATION);
2538 if (noGPSLocation != null) {
2539 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
2540 }
2541 } else {
2542 return new Location(location);
2543 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002544 return null;
2545 } finally {
2546 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002547 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002548 }
2549 }
2550
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002551 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002552 public boolean injectLocation(Location location) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002553 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2554 "Location Hardware permission not granted to inject location");
2555 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2556 "Access Fine Location permission not granted to inject Location");
2557
2558 if (location == null) {
2559 if (D) {
2560 Log.d(TAG, "injectLocation(): called with null location");
2561 }
2562 return false;
2563 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002564
Soonil Nagarkar68257742019-01-09 19:42:34 +00002565 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002566 LocationProvider provider = getLocationProviderLocked(location.getProvider());
2567 if (provider == null || !provider.isUseableLocked()) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002568 return false;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002569 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002570
2571 // NOTE: If last location is already available, location is not injected. If
2572 // provider's normal source (like a GPS chipset) have already provided an output
2573 // there is no need to inject this location.
2574 if (mLastLocation.get(provider.getName()) != null) {
2575 return false;
2576 }
2577
2578 updateLastLocationLocked(location, provider.getName());
2579 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002580 }
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002581 }
2582
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002583 @Override
2584 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2585 String packageName) {
2586 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002587 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2588 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002589 if (intent == null) {
2590 throw new IllegalArgumentException("invalid pending intent: " + null);
Victoria Lease56e675b2012-11-05 19:25:06 -08002591 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002592 checkPackageName(packageName);
2593 synchronized (mLock) {
2594 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2595 request.getProvider());
2596 // Require that caller can manage given document
2597 boolean callerHasLocationHardwarePermission =
2598 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2599 == PERMISSION_GRANTED;
2600 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2601 allowedResolutionLevel,
2602 callerHasLocationHardwarePermission);
2603
2604 if (D) {
2605 Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
2606 }
2607
2608 // geo-fence manager uses the public location API, need to clear identity
2609 int uid = Binder.getCallingUid();
2610 // TODO: http://b/23822629
2611 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
2612 // temporary measure until geofences work for secondary users
2613 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2614 return;
2615 }
2616 long identity = Binder.clearCallingIdentity();
2617 try {
2618 mGeofenceManager.addFence(sanitizedRequest, geofence, intent,
2619 allowedResolutionLevel,
2620 uid, packageName);
2621 } finally {
2622 Binder.restoreCallingIdentity(identity);
2623 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002624 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002625 }
2626
2627 @Override
2628 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002629 if (intent == null) {
2630 throw new IllegalArgumentException("invalid pending intent: " + null);
2631 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002632 checkPackageName(packageName);
2633
2634 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2635
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002636 // geo-fence manager uses the public location API, need to clear identity
2637 long identity = Binder.clearCallingIdentity();
2638 try {
2639 mGeofenceManager.removeFence(geofence, intent);
2640 } finally {
2641 Binder.restoreCallingIdentity(identity);
2642 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002643 }
2644
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002645 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002646 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002647 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002648 return false;
2649 }
2650
Anil Admal75b9fd62018-11-28 11:22:50 -08002651 // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
2652 // measurements listeners.
2653 return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002654 }
2655
Nick Pellye0fd6932012-07-11 10:26:13 -07002656 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002657 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002658 mGnssStatusProvider.removeListener(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 }
2660
Nick Pellye0fd6932012-07-11 10:26:13 -07002661 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002662 public boolean addGnssMeasurementsListener(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002663 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002664 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002665 return false;
2666 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002667
Soonil Nagarkar68257742019-01-09 19:42:34 +00002668 synchronized (mLock) {
2669 Identity callerIdentity
2670 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002671 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002672 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002673 long identity = Binder.clearCallingIdentity();
2674 try {
2675 if (isThrottlingExemptLocked(callerIdentity)
2676 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002677 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002678 return mGnssMeasurementsProvider.addListener(listener,
2679 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002680 }
2681 } finally {
2682 Binder.restoreCallingIdentity(identity);
2683 }
2684
2685 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002686 }
destradaaea8a8a62014-06-23 18:19:03 -07002687 }
2688
2689 @Override
gomo226b7b72018-12-12 16:49:39 -08002690 public void injectGnssMeasurementCorrections(
2691 GnssMeasurementCorrections measurementCorrections, String packageName) {
2692 mContext.enforceCallingPermission(
2693 android.Manifest.permission.LOCATION_HARDWARE,
2694 "Location Hardware permission not granted to inject GNSS measurement corrections.");
2695 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2696 mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
2697 } else {
2698 Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
2699 }
2700 }
2701
2702 @Override
2703 public int getGnssCapabilities(String packageName) {
2704 mContext.enforceCallingPermission(
2705 android.Manifest.permission.LOCATION_HARDWARE,
2706 "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
2707 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2708 return -1;
2709 }
2710 return mGnssMeasurementsProvider.getGnssCapabilities();
2711 }
2712
2713 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002714 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002715 if (mGnssMeasurementsProvider == null) {
2716 return;
2717 }
2718
Soonil Nagarkar68257742019-01-09 19:42:34 +00002719 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002720 mGnssMeasurementsListeners.remove(listener.asBinder());
2721 mGnssMeasurementsProvider.removeListener(listener);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002722 }
destradaaea8a8a62014-06-23 18:19:03 -07002723 }
2724
2725 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002726 public boolean addGnssNavigationMessageListener(
2727 IGnssNavigationMessageListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002728 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002729 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002730 return false;
2731 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002732
Soonil Nagarkar68257742019-01-09 19:42:34 +00002733 synchronized (mLock) {
2734 Identity callerIdentity
2735 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002736
Anil Admal75b9fd62018-11-28 11:22:50 -08002737 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002738 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002739 long identity = Binder.clearCallingIdentity();
2740 try {
2741 if (isThrottlingExemptLocked(callerIdentity)
2742 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002743 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002744 return mGnssNavigationMessageProvider.addListener(listener,
2745 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002746 }
2747 } finally {
2748 Binder.restoreCallingIdentity(identity);
2749 }
2750
2751 return true;
Wei Liu5241a4c2015-05-11 14:00:36 -07002752 }
destradaa4b3e3932014-07-21 18:01:47 -07002753 }
2754
2755 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002756 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2757 if (mGnssNavigationMessageProvider != null) {
2758 synchronized (mLock) {
2759 mGnssNavigationMessageListeners.remove(listener.asBinder());
2760 mGnssNavigationMessageProvider.removeListener(listener);
2761 }
2762 }
2763 }
2764
2765 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002766 public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
2767 if (providerName == null) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002768 // throw NullPointerException to remain compatible with previous implementation
2769 throw new NullPointerException();
2770 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002771 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002772 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2773 providerName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002774
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002775 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
2776 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
2777 != PERMISSION_GRANTED)) {
2778 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2779 }
2780
2781 LocationProvider provider = getLocationProviderLocked(providerName);
2782 if (provider != null) {
2783 provider.sendExtraCommandLocked(command, extras);
2784 }
2785
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002786 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002787 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002788 }
2789
Nick Pellye0fd6932012-07-11 10:26:13 -07002790 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002791 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002792 if (Binder.getCallingUid() != Process.myUid()) {
2793 throw new SecurityException(
2794 "calling sendNiResponse from outside of the system is not allowed");
2795 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002796 try {
2797 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002798 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002799 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002800 return false;
2801 }
2802 }
2803
Nick Pellye0fd6932012-07-11 10:26:13 -07002804 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002805 public ProviderProperties getProviderProperties(String providerName) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002806 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002807 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2808 providerName);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002809
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002810 LocationProvider provider = getLocationProviderLocked(providerName);
2811 if (provider == null) {
2812 return null;
2813 }
2814 return provider.getPropertiesLocked();
2815 }
Jason Monkb71218a2015-06-17 14:44:39 -04002816 }
2817
Wei Wang980b7c22018-12-06 17:53:00 -08002818 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002819 public String getNetworkProviderPackage() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002820 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002821 LocationProvider provider = getLocationProviderLocked(NETWORK_PROVIDER);
2822 if (provider == null) {
2823 return null;
2824 }
2825 return provider.getPackageLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +00002826 }
Maggie2a9409e2018-03-21 11:47:28 -07002827 }
2828
Maggie2a9409e2018-03-21 11:47:28 -07002829 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002830 public void setLocationControllerExtraPackage(String packageName) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002831 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2832 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002833 synchronized (mLock) {
2834 mLocationControllerExtraPackage = packageName;
2835 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002836 }
2837
2838 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002839 public String getLocationControllerExtraPackage() {
2840 synchronized (mLock) {
2841 return mLocationControllerExtraPackage;
2842 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002843 }
2844
2845 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002846 public void setLocationControllerExtraPackageEnabled(boolean enabled) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002847 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2848 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002849 synchronized (mLock) {
2850 mLocationControllerExtraPackageEnabled = enabled;
2851 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002852 }
2853
2854 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002855 public boolean isLocationControllerExtraPackageEnabled() {
2856 synchronized (mLock) {
2857 return mLocationControllerExtraPackageEnabled
2858 && (mLocationControllerExtraPackage != null);
2859 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002860 }
2861
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002862 private boolean isLocationEnabled() {
2863 return isLocationEnabledForUser(mCurrentUserId);
2864 }
2865
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002866 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002867 public boolean isLocationEnabledForUser(int userId) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002868 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002869 if (UserHandle.getCallingUserId() != userId) {
2870 mContext.enforceCallingOrSelfPermission(
2871 Manifest.permission.INTERACT_ACROSS_USERS,
2872 "Requires INTERACT_ACROSS_USERS permission");
2873 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002874
Soonil Nagarkar68257742019-01-09 19:42:34 +00002875 long identity = Binder.clearCallingIdentity();
2876 try {
Soonil Nagarkar42da1b12019-01-22 11:29:27 -08002877 return Settings.Secure.getIntForUser(
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002878 mContext.getContentResolver(),
2879 Settings.Secure.LOCATION_MODE,
Soonil Nagarkar42da1b12019-01-22 11:29:27 -08002880 Settings.Secure.LOCATION_MODE_OFF,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002881 userId) != Settings.Secure.LOCATION_MODE_OFF;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002882 } finally {
2883 Binder.restoreCallingIdentity(identity);
2884 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002885 }
2886
Maggie2a9409e2018-03-21 11:47:28 -07002887 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002888 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002889 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002890 if (UserHandle.getCallingUserId() != userId) {
2891 mContext.enforceCallingOrSelfPermission(
2892 Manifest.permission.INTERACT_ACROSS_USERS,
2893 "Requires INTERACT_ACROSS_USERS permission");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002894 }
2895
Maggie2a9409e2018-03-21 11:47:28 -07002896 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2897 // so we discourage its use
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002898 if (FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002899
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002900 synchronized (mLock) {
2901 LocationProvider provider = getLocationProviderLocked(providerName);
2902 return provider != null && provider.isUseableForUserLocked(userId);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002903 }
Maggie2a9409e2018-03-21 11:47:28 -07002904 }
2905
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002906 @GuardedBy("mLock")
2907 private boolean isLocationProviderLocked(int uid) {
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002908 if (uid == Process.SYSTEM_UID) {
2909 return true;
2910 }
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002911
David Christie1f141c12014-05-14 15:11:15 -07002912 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2913 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002914 return false;
2915 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002916 for (LocationProvider provider : mProviders) {
2917 String packageName = provider.getPackageLocked();
2918 if (packageName == null) {
2919 continue;
2920 }
2921 if (ArrayUtils.contains(packageNames, packageName)) {
David Christie1f141c12014-05-14 15:11:15 -07002922 return true;
2923 }
2924 }
2925 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002926 }
2927
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002928 @GuardedBy("mLock")
2929 private static boolean shouldBroadcastSafeLocked(
Laurent Tu75defb62012-11-01 16:21:52 -07002930 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002931 // Always broadcast the first update
2932 if (lastLoc == null) {
2933 return true;
2934 }
2935
Nick Pellyf1be6862012-05-15 10:53:42 -07002936 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002937 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002938 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2939 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002940 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002941 return false;
2942 }
2943
2944 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002945 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002946 if (minDistance > 0.0) {
2947 if (loc.distanceTo(lastLoc) <= minDistance) {
2948 return false;
2949 }
2950 }
2951
Laurent Tu75defb62012-11-01 16:21:52 -07002952 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002953 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002954 return false;
2955 }
2956
2957 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002958 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002959 }
2960
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002961 @GuardedBy("mLock")
2962 private void handleLocationChangedLocked(Location location, LocationProvider provider) {
2963 if (!mProviders.contains(provider)) {
2964 return;
2965 }
2966 if (!location.isComplete()) {
2967 Log.w(TAG, "Dropping incomplete location: " + location);
2968 return;
2969 }
2970
2971 if (!provider.isPassiveLocked()) {
2972 // notify passive provider of the new location
2973 mPassiveProvider.updateLocation(location);
2974 }
2975
Soonil Nagarkar68257742019-01-09 19:42:34 +00002976 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002977 long now = SystemClock.elapsedRealtime();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002978 updateLastLocationLocked(location, provider.getName());
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002979 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002980 Location lastLocation = mLastLocation.get(provider.getName());
Mike Lockwood4e50b782009-04-03 08:24:43 -07002981 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002982 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
2983 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07002984 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002985
David Christie1b9b7b12013-04-15 15:31:11 -07002986 // Update last known coarse interval location if enough time has passed.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002987 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider.getName());
David Christie1b9b7b12013-04-15 15:31:11 -07002988 if (lastLocationCoarseInterval == null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002989 lastLocationCoarseInterval = new Location(location);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002990 mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
David Christie1b9b7b12013-04-15 15:31:11 -07002991 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002992 long timeDiffNanos = location.getElapsedRealtimeNanos()
David Christie1b9b7b12013-04-15 15:31:11 -07002993 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
2994 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002995 lastLocationCoarseInterval.set(location);
David Christie1b9b7b12013-04-15 15:31:11 -07002996 }
2997 // Don't ever return a coarse location that is more recent than the allowed update
2998 // interval (i.e. don't allow an app to keep registering and unregistering for
2999 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003000 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07003001 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3002
Laurent Tu60ec50a2012-10-04 17:00:10 -07003003 // Skip if there are no UpdateRecords for this provider.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003004 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Laurent Tu60ec50a2012-10-04 17:00:10 -07003005 if (records == null || records.size() == 0) return;
3006
Victoria Lease09016ab2012-09-16 12:33:15 -07003007 // Fetch coarse location
3008 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07003009 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003010 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
3011 }
3012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003013 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003014 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07003015
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003016 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003017 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003018 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003019 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003020
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003021 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003022 if (!isCurrentProfileLocked(receiverUserId)
3023 && !isLocationProviderLocked(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003024 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003025 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003026 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003027 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003028 }
3029 continue;
3030 }
3031
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003032 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003033 if (D) {
3034 Log.d(TAG, "skipping loc update for blacklisted app: " +
3035 receiver.mIdentity.mPackageName);
3036 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003037 continue;
3038 }
3039
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003040 if (!reportLocationAccessNoThrow(
3041 receiver.mIdentity.mPid,
3042 receiver.mIdentity.mUid,
3043 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003044 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003045 if (D) {
3046 Log.d(TAG, "skipping loc update for no op app: " +
3047 receiver.mIdentity.mPackageName);
3048 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003049 continue;
3050 }
3051
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003052 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003053 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3054 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003055 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07003056 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003057 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003058 if (notifyLocation != null) {
3059 Location lastLoc = r.mLastFixBroadcast;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003060 if ((lastLoc == null)
3061 || shouldBroadcastSafeLocked(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003062 if (lastLoc == null) {
3063 lastLoc = new Location(notifyLocation);
3064 r.mLastFixBroadcast = lastLoc;
3065 } else {
3066 lastLoc.set(notifyLocation);
3067 }
3068 if (!receiver.callLocationChangedLocked(notifyLocation)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003069 Slog.w(TAG, "RemoteException calling onLocationChanged on "
3070 + receiver);
Victoria Lease09016ab2012-09-16 12:33:15 -07003071 receiverDead = true;
3072 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003073 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003074 }
3075 }
3076
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003077 // TODO: location provider status callbacks have been disabled and deprecated, and are
3078 // guarded behind this setting now. should be removed completely post-Q
3079 if (Settings.Global.getInt(mContext.getContentResolver(),
3080 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003081 long newStatusUpdateTime = provider.getStatusUpdateTimeLocked();
3082 Bundle extras = new Bundle();
3083 int status = provider.getStatusLocked(extras);
3084
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003085 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3086 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003087 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003088
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003089 r.mLastStatusBroadcast = newStatusUpdateTime;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003090 if (!receiver.callStatusChangedLocked(provider.getName(), status, extras)) {
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003091 receiverDead = true;
3092 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3093 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003094 }
3095 }
3096
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003097 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003098 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003099 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003100 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003101 }
3102 deadUpdateRecords.add(r);
3103 }
3104 // track dead receivers
3105 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003106 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003107 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003108 }
3109 if (!deadReceivers.contains(receiver)) {
3110 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003111 }
3112 }
3113 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003114
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003115 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003116 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003117 for (Receiver receiver : deadReceivers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003118 removeUpdatesLocked(receiver);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003119 }
3120 }
3121 if (deadUpdateRecords != null) {
3122 for (UpdateRecord r : deadUpdateRecords) {
3123 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003124 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003125 applyRequirementsLocked(provider);
Victoria Lease8b38b292012-12-04 15:04:43 -08003126 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003127 }
3128
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003129 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00003130 private void updateLastLocationLocked(Location location, String provider) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003131 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3132 Location lastNoGPSLocation;
3133 Location lastLocation = mLastLocation.get(provider);
3134 if (lastLocation == null) {
3135 lastLocation = new Location(provider);
3136 mLastLocation.put(provider, lastLocation);
3137 } else {
3138 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3139 if (noGPSLocation == null && lastNoGPSLocation != null) {
3140 // New location has no no-GPS location: adopt last no-GPS location. This is set
3141 // directly into location because we do not want to notify COARSE clients.
3142 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3143 }
3144 }
3145 lastLocation.set(location);
3146 }
3147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148 // Geocoder
3149
Nick Pellye0fd6932012-07-11 10:26:13 -07003150 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003151 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003152 return mGeocodeProvider != null;
3153 }
3154
Nick Pellye0fd6932012-07-11 10:26:13 -07003155 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003156 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003157 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003158 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003159 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3160 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003161 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003162 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163 }
3164
Mike Lockwooda55c3212009-04-15 11:10:11 -04003165
Nick Pellye0fd6932012-07-11 10:26:13 -07003166 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003168 double lowerLeftLatitude, double lowerLeftLongitude,
3169 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003170 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003171
3172 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003173 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3174 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3175 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003176 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003177 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003178 }
3179
3180 // Mock Providers
3181
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003182 private boolean canCallerAccessMockLocation(String opPackageName) {
3183 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3184 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003185 }
3186
Nick Pellye0fd6932012-07-11 10:26:13 -07003187 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003188 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003189 if (!canCallerAccessMockLocation(opPackageName)) {
3190 return;
3191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003192
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003193 if (PASSIVE_PROVIDER.equals(name)) {
Mike Lockwooda4903f22010-02-17 06:42:23 -05003194 throw new IllegalArgumentException("Cannot mock the passive location provider");
3195 }
3196
Soonil Nagarkar68257742019-01-09 19:42:34 +00003197 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003198 long identity = Binder.clearCallingIdentity();
3199 try {
3200 LocationProvider oldProvider = getLocationProviderLocked(name);
3201 if (oldProvider != null) {
3202 if (oldProvider.isMock()) {
3203 throw new IllegalArgumentException(
3204 "Provider \"" + name + "\" already exists");
3205 }
3206
3207 removeProviderLocked(oldProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003208 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003209
3210 MockLocationProvider mockProviderManager = new MockLocationProvider(name);
3211 addProviderLocked(mockProviderManager);
3212 mockProviderManager.attachLocked(new MockProvider(mockProviderManager, properties));
3213 } finally {
3214 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003215 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003216 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003217 }
3218
Nick Pellye0fd6932012-07-11 10:26:13 -07003219 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003220 public void removeTestProvider(String name, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003221 if (!canCallerAccessMockLocation(opPackageName)) {
3222 return;
3223 }
3224
Soonil Nagarkar68257742019-01-09 19:42:34 +00003225 synchronized (mLock) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003226 long identity = Binder.clearCallingIdentity();
3227 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003228 LocationProvider testProvider = getLocationProviderLocked(name);
3229 if (testProvider == null || !testProvider.isMock()) {
3230 throw new IllegalArgumentException("Provider \"" + name + "\" unknown");
3231 }
3232
3233 removeProviderLocked(testProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003234
Soonil Nagarkar68257742019-01-09 19:42:34 +00003235 // reinstate real provider if available
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003236 LocationProvider realProvider = null;
3237 for (LocationProvider provider : mRealProviders) {
3238 if (name.equals(provider.getName())) {
3239 realProvider = provider;
3240 break;
3241 }
3242 }
3243
Soonil Nagarkar68257742019-01-09 19:42:34 +00003244 if (realProvider != null) {
3245 addProviderLocked(realProvider);
3246 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003247 } finally {
3248 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003249 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 }
3252
Nick Pellye0fd6932012-07-11 10:26:13 -07003253 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003254 public void setTestProviderLocation(String providerName, Location location,
Soonil Nagarkar68257742019-01-09 19:42:34 +00003255 String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003256 if (!canCallerAccessMockLocation(opPackageName)) {
3257 return;
3258 }
3259
Soonil Nagarkar68257742019-01-09 19:42:34 +00003260 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003261 LocationProvider testProvider = getLocationProviderLocked(providerName);
3262 if (testProvider == null || !testProvider.isMock()) {
3263 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003264 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003265
3266 String locationProvider = location.getProvider();
3267 if (!TextUtils.isEmpty(locationProvider) && !providerName.equals(locationProvider)) {
3268 // The location has an explicit provider that is different from the mock
3269 // provider name. The caller may be trying to fool us via b/33091107.
3270 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3271 providerName + "!=" + location.getProvider());
3272 }
3273
3274 ((MockLocationProvider) testProvider).setLocationLocked(location);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003275 }
3276 }
3277
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003278 @Override
3279 public void setTestProviderEnabled(String providerName, boolean enabled, String opPackageName) {
3280 if (!canCallerAccessMockLocation(opPackageName)) {
3281 return;
3282 }
3283
3284 synchronized (mLock) {
3285 LocationProvider testProvider = getLocationProviderLocked(providerName);
3286 if (testProvider == null || !testProvider.isMock()) {
3287 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3288 }
3289
3290 ((MockLocationProvider) testProvider).setEnabledLocked(enabled);
3291 }
3292 }
3293
3294 @Override
3295 public void setTestProviderStatus(String providerName, int status, Bundle extras,
3296 long updateTime, String opPackageName) {
3297 if (!canCallerAccessMockLocation(opPackageName)) {
3298 return;
3299 }
3300
3301 synchronized (mLock) {
3302 LocationProvider testProvider = getLocationProviderLocked(providerName);
3303 if (testProvider == null || !testProvider.isMock()) {
3304 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3305 }
3306
3307 ((MockLocationProvider) testProvider).setStatusLocked(status, extras, updateTime);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003308 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003310
3311 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003312 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003313 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003314
Soonil Nagarkar68257742019-01-09 19:42:34 +00003315 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003316 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3317 if (mGnssMetricsProvider != null) {
3318 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3319 }
3320 return;
3321 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003322 pw.println("Current Location Manager state:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003323 pw.println(" Location Mode: " + isLocationEnabled());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003324 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003325 for (Receiver receiver : mReceivers.values()) {
3326 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 }
David Christie2ff96af2014-01-30 16:09:37 -08003328 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003329 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3330 pw.println(" " + entry.getKey() + ":");
3331 for (UpdateRecord record : entry.getValue()) {
3332 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 }
3334 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003335 pw.println(" Active GnssMeasurement Listeners:");
3336 for (Identity identity : mGnssMeasurementsListeners.values()) {
3337 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3338 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3339 }
3340 pw.println(" Active GnssNavigationMessage Listeners:");
3341 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3342 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3343 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3344 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003345 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003346 for (LocationProvider provider : mProviders) {
3347 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003348 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003349 + ((LocationProviderProxy) provider.mProvider)
3350 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003351 }
3352 }
David Christie2ff96af2014-01-30 16:09:37 -08003353 pw.println(" Historical Records by Provider:");
3354 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3355 : mRequestStatistics.statistics.entrySet()) {
3356 PackageProviderKey key = entry.getKey();
3357 PackageStatistics stats = entry.getValue();
3358 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3359 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003360 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003361 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3362 String provider = entry.getKey();
3363 Location location = entry.getValue();
3364 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003366
David Christie1b9b7b12013-04-15 15:31:11 -07003367 pw.println(" Last Known Locations Coarse Intervals:");
3368 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3369 String provider = entry.getKey();
3370 Location location = entry.getValue();
3371 pw.println(" " + provider + ": " + location);
3372 }
3373
Nick Pellye0fd6932012-07-11 10:26:13 -07003374 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003375
Nick Pelly4035f5a2012-08-17 14:43:49 -07003376 pw.append(" ");
3377 mBlacklist.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003378
Wei Wang980b7c22018-12-06 17:53:00 -08003379 if (mLocationControllerExtraPackage != null) {
3380 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
3381 + " enabled: " + mLocationControllerExtraPackageEnabled);
3382 }
3383
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003384 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3385 pw.println(" Throttling Whitelisted Packages:");
3386 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3387 pw.println(" " + packageName);
3388 }
3389 }
3390
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003391 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003392 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003393
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003394 if (args.length > 0 && "short".equals(args[0])) {
3395 return;
3396 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003397 for (LocationProvider provider : mProviders) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003398 provider.dumpLocked(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003399 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003400 if (mGnssBatchingInProgress) {
3401 pw.println(" GNSS batching in progress");
3402 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003403 }
3404 }
3405}