blob: 869d564b4329685c5aa127529fa1a5c494f1c3f4 [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;
49import android.hardware.location.ActivityRecognitionHardware;
50import android.location.Address;
51import android.location.Criteria;
52import android.location.GeocoderParams;
53import android.location.Geofence;
gomo226b7b72018-12-12 16:49:39 -080054import android.location.GnssMeasurementCorrections;
Maggieaa080f92018-01-04 15:35:11 -080055import android.location.IBatchedLocationCallback;
56import android.location.IGnssMeasurementsListener;
57import android.location.IGnssNavigationMessageListener;
58import android.location.IGnssStatusListener;
Maggieaa080f92018-01-04 15:35:11 -080059import android.location.IGpsGeofenceHardware;
60import android.location.ILocationListener;
61import android.location.ILocationManager;
62import android.location.INetInitiatedListener;
63import android.location.Location;
64import android.location.LocationManager;
Maggieaa080f92018-01-04 15:35:11 -080065import android.location.LocationRequest;
66import android.os.Binder;
67import android.os.Bundle;
68import android.os.Handler;
69import android.os.IBinder;
70import android.os.Looper;
Maggieaa080f92018-01-04 15:35:11 -080071import android.os.PowerManager;
72import android.os.Process;
73import android.os.RemoteException;
74import android.os.SystemClock;
75import android.os.UserHandle;
76import android.os.UserManager;
77import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000078import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080079import android.provider.Settings;
80import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080081import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080082import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080083import android.util.EventLog;
84import android.util.Log;
85import android.util.Slog;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -070086
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080087import com.android.internal.annotations.GuardedBy;
destradaaea8a8a62014-06-23 18:19:03 -070088import com.android.internal.content.PackageMonitor;
89import com.android.internal.location.ProviderProperties;
90import com.android.internal.location.ProviderRequest;
91import com.android.internal.os.BackgroundThread;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070092import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060093import com.android.internal.util.DumpUtils;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080094import com.android.internal.util.Preconditions;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070095import com.android.server.location.AbstractLocationProvider;
destradaaa4fa3b52014-07-09 10:46:39 -070096import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070097import com.android.server.location.GeocoderProxy;
98import com.android.server.location.GeofenceManager;
99import com.android.server.location.GeofenceProxy;
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700100import com.android.server.location.GnssBatchingProvider;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800101import com.android.server.location.GnssLocationProvider;
102import com.android.server.location.GnssMeasurementsProvider;
103import com.android.server.location.GnssNavigationMessageProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800104import com.android.server.location.GnssStatusListenerHelper;
destradaaea8a8a62014-06-23 18:19:03 -0700105import com.android.server.location.LocationBlacklist;
106import com.android.server.location.LocationFudger;
destradaaea8a8a62014-06-23 18:19:03 -0700107import com.android.server.location.LocationProviderProxy;
108import com.android.server.location.LocationRequestStatistics;
109import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
110import com.android.server.location.LocationRequestStatistics.PackageStatistics;
111import com.android.server.location.MockProvider;
112import com.android.server.location.PassiveProvider;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -0700113
Mike Lockwood43e33f22010-03-26 10:41:48 -0400114import java.io.FileDescriptor;
115import java.io.PrintWriter;
116import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700117import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400118import java.util.HashMap;
119import java.util.HashSet;
120import java.util.List;
121import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800122import java.util.Map.Entry;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800123import java.util.NoSuchElementException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124
125/**
126 * The service class that manages LocationProviders and issues location
127 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800129public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800131 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700132
Olivier Gaillard7a222662017-11-20 16:07:24 +0000133 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134
Victoria Lease37425c32012-10-16 16:08:48 -0700135 // Location resolution level: no location data whatsoever
136 private static final int RESOLUTION_LEVEL_NONE = 0;
137 // Location resolution level: coarse location data only
138 private static final int RESOLUTION_LEVEL_COARSE = 1;
139 // Location resolution level: fine location data
140 private static final int RESOLUTION_LEVEL_FINE = 2;
141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700143 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700144
145 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700146 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700147 private static final String FUSED_LOCATION_SERVICE_ACTION =
148 "com.android.location.service.FusedLocationProvider";
149
David Christie1b9b7b12013-04-15 15:31:11 -0700150 private static final long NANOS_PER_MILLI = 1000000L;
151
David Christie0b837452013-07-29 16:02:13 -0700152 // The maximum interval a location request can have and still be considered "high power".
153 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
154
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700155 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800156 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700157
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800158 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800159 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800160
Wei Wangdd070f22018-06-21 11:29:40 -0700161 // Default value for maximum age of last location returned to applications with foreground-only
162 // location permissions.
163 private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
164
Nick Pellyf1be6862012-05-15 10:53:42 -0700165 // Location Providers may sometimes deliver location updates
166 // slightly faster that requested - provide grace period so
167 // we don't unnecessarily filter events that are otherwise on
168 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700170
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700171 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
172
Soonil Nagarkar68257742019-01-09 19:42:34 +0000173 private final Object mLock = new Object();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800174 private final Context mContext;
175 private final Handler mHandler;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700176
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800177 private AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700178 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700179 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800180 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700181 private UserManager mUserManager;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800182
183 private GeofenceManager mGeofenceManager;
184 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 private GeocoderProxy mGeocodeProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800186 private GnssStatusListenerHelper mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700187 private INetInitiatedListener mNetInitiatedListener;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700188 private PassiveProvider mPassiveProvider; // track passive provider for special cases
189 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800190 private GnssMeasurementsProvider mGnssMeasurementsProvider;
191 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800192 @GuardedBy("mLock")
Wei Wang980b7c22018-12-06 17:53:00 -0800193 private String mLocationControllerExtraPackage;
194 private boolean mLocationControllerExtraPackageEnabled;
Wei Liu5241a4c2015-05-11 14:00:36 -0700195 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700196
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800197 // list of currently active providers
198 @GuardedBy("mLock")
199 private final ArrayList<LocationProvider> mProviders = new ArrayList<>();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000200
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800201 // list of non-mock providers, so that when mock providers replace real providers, they can be
202 // later re-replaced
203 @GuardedBy("mLock")
204 private final ArrayList<LocationProvider> mRealProviders = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800206 @GuardedBy("mLock")
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800207 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700208 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800209 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700210
David Christie2ff96af2014-01-30 16:09:37 -0800211 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
212
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700213 // mapping from provider name to last known location
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800214 @GuardedBy("mLock")
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800215 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216
David Christie1b9b7b12013-04-15 15:31:11 -0700217 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
218 // locations stored here are not fudged for coarse permissions.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800219 @GuardedBy("mLock")
David Christie1b9b7b12013-04-15 15:31:11 -0700220 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800221 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700222
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800223 private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800224
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800225 @GuardedBy("mLock")
Wyatt Riley11cc7492018-01-17 08:48:27 -0800226 private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800227
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800228 @GuardedBy("mLock")
Wyatt Riley11cc7492018-01-17 08:48:27 -0800229 private final ArrayMap<IBinder, Identity>
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800230 mGnssNavigationMessageListeners = new ArrayMap<>();
231
Victoria Lease38389b62012-09-30 11:44:22 -0700232 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700233 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800234 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700235
Lifu Tang9363b942016-02-16 18:07:00 -0800236 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800237
Siddharth Raybb608c82017-03-16 11:33:34 -0700238 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700239
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700240 private GnssBatchingProvider mGnssBatchingProvider;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800241 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800242 private IBatchedLocationCallback mGnssBatchingCallback;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800243 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800244 private LinkedCallback mGnssBatchingDeathCallback;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800245 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800246 private boolean mGnssBatchingInProgress = false;
247
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700248 public LocationManagerService(Context context) {
249 super();
250 mContext = context;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800251 mHandler = BackgroundThread.getHandler();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800252
Svet Ganovadc1cf42015-06-15 16:36:24 -0700253 // Let the package manager query which are the default location
254 // providers as they get certain permissions granted by default.
255 PackageManagerInternal packageManagerInternal = LocalServices.getService(
256 PackageManagerInternal.class);
257 packageManagerInternal.setLocationPackagesProvider(
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700258 userId -> mContext.getResources().getStringArray(
259 com.android.internal.R.array.config_locationProviderPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700260
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700261 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700262 }
263
Svetoslav Ganova0027152013-06-25 14:59:53 -0700264 public void systemRunning() {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000265 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800266 initializeLocked();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800267 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800268 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700269
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800270 @GuardedBy("mLock")
271 private void initializeLocked() {
272 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
273 mPackageManager = mContext.getPackageManager();
274 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
275 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
276 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
277
278 mLocationFudger = new LocationFudger(mContext, mHandler);
279 mBlacklist = new LocationBlacklist(mContext, mHandler);
280 mBlacklist.init();
281 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
282
283 // prepare providers
284 initializeProvidersLocked();
285
286 // add listeners
287 mAppOps.startWatchingMode(
288 AppOpsManager.OP_COARSE_LOCATION,
289 null,
290 AppOpsManager.WATCH_FOREGROUND_CHANGES,
291 new AppOpsManager.OnOpChangedInternalListener() {
292 public void onOpChanged(int op, String packageName) {
293 synchronized (mLock) {
294 onAppOpChangedLocked();
295 }
296 }
297 });
298 mPackageManager.addOnPermissionsChangeListener(
299 uid -> {
300 synchronized (mLock) {
301 onPermissionsChangedLocked();
302 }
303 });
304
305 mActivityManager.addOnUidImportanceListener(
306 (uid, importance) -> {
307 synchronized (mLock) {
308 onUidImportanceChangedLocked(uid, importance);
309 }
310 },
311 FOREGROUND_IMPORTANCE_CUTOFF);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700312 mContext.getContentResolver().registerContentObserver(
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800313 Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), true,
314 new ContentObserver(mHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800315 @Override
316 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000317 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800318 onLocationModeChangedLocked(true);
319 }
320 }
321 }, UserHandle.USER_ALL);
322 mContext.getContentResolver().registerContentObserver(
323 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
324 new ContentObserver(mHandler) {
325 @Override
326 public void onChange(boolean selfChange) {
327 synchronized (mLock) {
328 onProviderAllowedChangedLocked(true);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000329 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800330 }
331 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800332 mContext.getContentResolver().registerContentObserver(
333 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
334 true,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800335 new ContentObserver(mHandler) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800336 @Override
337 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000338 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800339 onBackgroundThrottleIntervalChangedLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000340 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800341 }
342 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800343 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800344 Settings.Global.getUriFor(
345 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
346 true,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800347 new ContentObserver(mHandler) {
gomo48f1a642017-11-10 20:35:46 -0800348 @Override
349 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000350 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800351 onBackgroundThrottleWhitelistChangedLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000352 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800353 }
gomo48f1a642017-11-10 20:35:46 -0800354 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700355
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800356 new PackageMonitor() {
357 @Override
358 public void onPackageDisappeared(String packageName, int reason) {
359 synchronized (mLock) {
360 LocationManagerService.this.onPackageDisappearedLocked(packageName);
361 }
362 }
363 }.register(mContext, mHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700364
Victoria Lease38389b62012-09-30 11:44:22 -0700365 IntentFilter intentFilter = new IntentFilter();
366 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700367 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
368 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700369
370 mContext.registerReceiverAsUser(new BroadcastReceiver() {
371 @Override
372 public void onReceive(Context context, Intent intent) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800373 synchronized (mLock) {
374 String action = intent.getAction();
375 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
376 onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
377 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
378 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
379 onUserProfilesChangedLocked();
380 }
Victoria Lease38389b62012-09-30 11:44:22 -0700381 }
382 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800383 }, UserHandle.ALL, intentFilter, null, mHandler);
384
385 // switching the user from null to system here performs the bulk of the initialization work.
386 // the user being changed will cause a reload of all user specific settings, which causes
387 // provider initialization, and propagates changes until a steady state is reached
388 mCurrentUserId = UserHandle.USER_NULL;
389 onUserChangedLocked(UserHandle.USER_SYSTEM);
390
391 // initialize in-memory settings values
392 onBackgroundThrottleWhitelistChangedLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700393 }
394
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800395 @GuardedBy("mLock")
396 private void onAppOpChangedLocked() {
397 for (Receiver receiver : mReceivers.values()) {
398 receiver.updateMonitoring(true);
399 }
400 for (LocationProvider p : mProviders) {
401 applyRequirementsLocked(p);
402 }
403 }
404
405 @GuardedBy("mLock")
406 private void onPermissionsChangedLocked() {
407 for (LocationProvider p : mProviders) {
408 applyRequirementsLocked(p);
409 }
410 }
411
412 @GuardedBy("mLock")
413 private void onLocationModeChangedLocked(boolean broadcast) {
414 for (LocationProvider p : mProviders) {
415 p.onLocationModeChangedLocked();
416 }
417
418 if (broadcast) {
419 mContext.sendBroadcastAsUser(
420 new Intent(LocationManager.MODE_CHANGED_ACTION),
421 UserHandle.ALL);
422 }
423 }
424
425 @GuardedBy("mLock")
426 private void onProviderAllowedChangedLocked(boolean broadcast) {
427 for (LocationProvider p : mProviders) {
428 p.onAllowedChangedLocked();
429 }
430
431 if (broadcast) {
432 mContext.sendBroadcastAsUser(
433 new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
434 UserHandle.ALL);
435 }
436 }
437
438 @GuardedBy("mLock")
439 private void onPackageDisappearedLocked(String packageName) {
440 ArrayList<Receiver> deadReceivers = null;
441
442 for (Receiver receiver : mReceivers.values()) {
443 if (receiver.mIdentity.mPackageName.equals(packageName)) {
444 if (deadReceivers == null) {
445 deadReceivers = new ArrayList<>();
446 }
447 deadReceivers.add(receiver);
448 }
449 }
450
451 // perform removal outside of mReceivers loop
452 if (deadReceivers != null) {
453 for (Receiver receiver : deadReceivers) {
454 removeUpdatesLocked(receiver);
455 }
456 }
457 }
458
459 @GuardedBy("mLock")
460 private void onUidImportanceChangedLocked(int uid, int importance) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700461 boolean foreground = isImportanceForeground(importance);
462 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800463 for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
464 String provider = entry.getKey();
465 for (UpdateRecord record : entry.getValue()) {
466 if (record.mReceiver.mIdentity.mUid == uid
467 && record.mIsForegroundUid != foreground) {
gomo48f1a642017-11-10 20:35:46 -0800468 if (D) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800469 Log.d(TAG, "request from uid " + uid + " is now "
gomo48f1a642017-11-10 20:35:46 -0800470 + (foreground ? "foreground" : "background)"));
471 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800472 record.updateForeground(foreground);
473
474 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
475 affectedProviders.add(provider);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700476 }
477 }
478 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800479 }
480 for (String provider : affectedProviders) {
481 applyRequirementsLocked(provider);
482 }
Anil Admal75b9fd62018-11-28 11:22:50 -0800483
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800484 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
485 Identity callerIdentity = entry.getValue();
486 if (callerIdentity.mUid == uid) {
487 if (D) {
488 Log.d(TAG, "gnss measurements listener from uid " + uid
489 + " is now " + (foreground ? "foreground" : "background)"));
490 }
491 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
492 mGnssMeasurementsProvider.addListener(
493 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
494 callerIdentity.mUid, callerIdentity.mPackageName);
495 } else {
496 mGnssMeasurementsProvider.removeListener(
497 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
498 }
499 }
500 }
501
502 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
503 Identity callerIdentity = entry.getValue();
504 if (callerIdentity.mUid == uid) {
505 if (D) {
506 Log.d(TAG, "gnss navigation message listener from uid "
507 + uid + " is now "
508 + (foreground ? "foreground" : "background)"));
509 }
510 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
511 mGnssNavigationMessageProvider.addListener(
512 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
513 callerIdentity.mUid, callerIdentity.mPackageName);
514 } else {
515 mGnssNavigationMessageProvider.removeListener(
516 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
517 }
518 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700519 }
520 }
521
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800522 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700523 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800524 }
525
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800526 @GuardedBy("mLock")
527 private void onBackgroundThrottleIntervalChangedLocked() {
528 for (LocationProvider provider : mProviders) {
529 applyRequirementsLocked(provider);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000530 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800531 }
532
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800533 @GuardedBy("mLock")
534 private void onBackgroundThrottleWhitelistChangedLocked() {
535 String setting = Settings.Global.getString(
536 mContext.getContentResolver(),
537 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
538 if (setting == null) {
539 setting = "";
540 }
541
542 mBackgroundThrottlePackageWhitelist.clear();
543 mBackgroundThrottlePackageWhitelist.addAll(
544 SystemConfig.getInstance().getAllowUnthrottledLocation());
545 mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(",")));
546
547 for (LocationProvider p : mProviders) {
548 applyRequirementsLocked(p);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000549 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800550 }
551
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800552 @GuardedBy("mLock")
553 private void onUserProfilesChangedLocked() {
554 mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(mCurrentUserId);
555 }
556
557 @GuardedBy("mLock")
558 private boolean isCurrentProfileLocked(int userId) {
559 return ArrayUtils.contains(mCurrentUserProfiles, userId);
560 }
561
562 @GuardedBy("mLock")
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700563 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500564 PackageManager pm = mContext.getPackageManager();
565 String systemPackageName = mContext.getPackageName();
566 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
567
568 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
569 new Intent(FUSED_LOCATION_SERVICE_ACTION),
570 PackageManager.GET_META_DATA, mCurrentUserId);
571 for (ResolveInfo rInfo : rInfos) {
572 String packageName = rInfo.serviceInfo.packageName;
573
574 // Check that the signature is in the list of supported sigs. If it's not in
575 // this list the standard provider binding logic won't bind to it.
576 try {
577 PackageInfo pInfo;
578 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
579 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
580 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
581 ", but has wrong signature, ignoring");
582 continue;
583 }
584 } catch (NameNotFoundException e) {
585 Log.e(TAG, "missing package: " + packageName);
586 continue;
587 }
588
589 // Get the version info
590 if (rInfo.serviceInfo.metaData == null) {
591 Log.w(TAG, "Found fused provider without metadata: " + packageName);
592 continue;
593 }
594
595 int version = rInfo.serviceInfo.metaData.getInt(
596 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
597 if (version == 0) {
598 // This should be the fallback fused location provider.
599
600 // Make sure it's in the system partition.
601 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
602 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
603 continue;
604 }
605
606 // Check that the fallback is signed the same as the OS
607 // as a proxy for coreApp="true"
608 if (pm.checkSignatures(systemPackageName, packageName)
609 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800610 if (D) {
611 Log.d(TAG, "Fallback candidate not signed the same as system: "
612 + packageName);
613 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500614 continue;
615 }
616
617 // Found a valid fallback.
618 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
619 return;
620 } else {
621 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
622 }
623 }
624
625 throw new IllegalStateException("Unable to find a fused location provider that is in the "
626 + "system partition with version 0 and signed with the platform certificate. "
627 + "Such a package is needed to provide a default fused location provider in the "
628 + "event that no other fused location provider has been installed or is currently "
629 + "available. For example, coreOnly boot mode when decrypting the data "
630 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
631 }
632
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800633 @GuardedBy("mLock")
634 private void initializeProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700635 // create a passive location provider, which is always enabled
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800636 LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000637 addProviderLocked(passiveProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800638 mPassiveProvider = new PassiveProvider(passiveProviderManager);
639 passiveProviderManager.attachLocked(mPassiveProvider);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700640
Lifu Tang30f95a72016-01-07 23:20:38 -0800641 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700642 // Create a gps location provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800643 LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
644 mRealProviders.add(gnssProviderManager);
645 addProviderLocked(gnssProviderManager);
646
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700647 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
648 gnssProviderManager,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800649 mHandler.getLooper());
650 gnssProviderManager.attachLocked(gnssProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700651
Lifu Tang9363b942016-02-16 18:07:00 -0800652 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800653 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700654 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800655 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
656 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
Lifu Tang818aa2c2016-02-01 01:52:00 -0800657 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
658 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800659 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700660 }
661
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700662 /*
663 Load package name(s) containing location provider support.
664 These packages can contain services implementing location providers:
665 Geocoder Provider, Network Location Provider, and
666 Fused Location Provider. They will each be searched for
667 service components implementing these providers.
668 The location framework also has support for installation
669 of new location providers at run-time. The new package does not
670 have to be explicitly listed here, however it must have a signature
671 that matches the signature of at least one package on this list.
672 */
673 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500674 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700675 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800676 if (D) {
677 Log.d(TAG, "certificates for location providers pulled from: " +
678 Arrays.toString(pkgs));
679 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500680
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700681 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700682
683 // bind to network provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800684 LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER, true);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700685 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
686 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700687 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700688 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700689 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
690 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700691 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700692 if (networkProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800693 mRealProviders.add(networkProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000694 addProviderLocked(networkProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800695 networkProviderManager.attachLocked(networkProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700696 } else {
gomo48f1a642017-11-10 20:35:46 -0800697 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700698 }
699
700 // bind to fused provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800701 LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700702 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700703 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700704 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700705 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700706 com.android.internal.R.bool.config_enableFusedLocationOverlay,
707 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700708 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700709 if (fusedProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800710 mRealProviders.add(fusedProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000711 addProviderLocked(fusedProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800712 fusedProviderManager.attachLocked(fusedProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700713 } else {
714 Slog.e(TAG, "no fused location provider found",
715 new IllegalStateException("Location service needs a fused location provider"));
716 }
717
718 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700719 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
720 com.android.internal.R.bool.config_enableGeocoderOverlay,
721 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700722 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700723 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800724 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700725 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700726
destradaaf9a274c2014-07-25 15:11:56 -0700727 // bind to geofence provider
728 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800729 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700730 com.android.internal.R.string.config_geofenceProviderPackageName,
731 com.android.internal.R.array.config_locationProviderPackageNames,
Wei Liu5241a4c2015-05-11 14:00:36 -0700732 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900733 null);
destradaaf9a274c2014-07-25 15:11:56 -0700734 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800735 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700736 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900737
destradaa6e2fe752015-06-23 17:25:53 -0700738 // bind to hardware activity recognition
739 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
740 ActivityRecognitionHardware activityRecognitionHardware = null;
741 if (activityRecognitionHardwareIsSupported) {
742 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700743 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700744 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700745 }
destradaa6e2fe752015-06-23 17:25:53 -0700746 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
747 mContext,
destradaa6e2fe752015-06-23 17:25:53 -0700748 activityRecognitionHardwareIsSupported,
749 activityRecognitionHardware,
750 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
751 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
752 com.android.internal.R.array.config_locationProviderPackageNames);
753 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700754 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700755 }
destradaaa4fa3b52014-07-09 10:46:39 -0700756
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900757 String[] testProviderStrings = resources.getStringArray(
758 com.android.internal.R.array.config_testLocationProviders);
759 for (String testProviderString : testProviderStrings) {
760 String fragments[] = testProviderString.split(",");
761 String name = fragments[0].trim();
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900762 ProviderProperties properties = new ProviderProperties(
763 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
764 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
765 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
766 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
767 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
768 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
769 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
770 Integer.parseInt(fragments[8]) /* powerRequirement */,
771 Integer.parseInt(fragments[9]) /* accuracy */);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800772 LocationProvider testProviderManager = new LocationProvider(name);
773 addProviderLocked(testProviderManager);
774 new MockProvider(testProviderManager, properties);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900775 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700776 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700777
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800778 @GuardedBy("mLock")
779 private void onUserChangedLocked(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800780 if (mCurrentUserId == userId) {
781 return;
782 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800783
784 // this call has the side effect of forcing a write to the LOCATION_MODE setting in an OS
785 // upgrade case, and ensures that if anyone checks the LOCATION_MODE setting directly, they
786 // will see it in an appropriate state (at least after that user becomes foreground for the
787 // first time...)
788 isLocationEnabledForUser(userId);
789
790 // let providers know the current user is on the way out before changing the user
791 for (LocationProvider p : mProviders) {
792 p.onUserChangingLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000793 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800794
795 mCurrentUserId = userId;
796 onUserProfilesChangedLocked();
797
798 mBlacklist.switchUser(userId);
799
800 // if the user changes, per-user settings may also have changed
801 onLocationModeChangedLocked(false);
802 onProviderAllowedChangedLocked(false);
Victoria Lease38389b62012-09-30 11:44:22 -0700803 }
804
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800805 private static final class Identity {
806 final int mUid;
807 final int mPid;
808 final String mPackageName;
809
810 Identity(int uid, int pid, String packageName) {
811 mUid = uid;
812 mPid = pid;
813 mPackageName = packageName;
814 }
815 }
816
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700817 private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
818
819 private final String mName;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700820
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800821 // whether this provider should respect LOCATION_PROVIDERS_ALLOWED (ie gps and network)
822 private final boolean mIsManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700823
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800824 // remember to clear binder identity before invoking any provider operation
825 @GuardedBy("mLock")
826 @Nullable protected AbstractLocationProvider mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700827
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800828 @GuardedBy("mLock")
829 private boolean mUseable; // combined state
830 @GuardedBy("mLock")
831 private boolean mAllowed; // state of LOCATION_PROVIDERS_ALLOWED
832 @GuardedBy("mLock")
833 private boolean mEnabled; // state of provider
834
835 @GuardedBy("mLock")
836 @Nullable private ProviderProperties mProperties;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700837
838 private LocationProvider(String name) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800839 this(name, false);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700840 }
841
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800842 private LocationProvider(String name, boolean isManagedBySettings) {
843 mName = name;
844 mIsManagedBySettings = isManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700845
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800846 mProvider = null;
847 mUseable = false;
848 mAllowed = !mIsManagedBySettings;
849 mEnabled = false;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700850 mProperties = null;
851 }
852
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800853 @GuardedBy("mLock")
854 public void attachLocked(AbstractLocationProvider provider) {
855 checkNotNull(provider);
856 checkState(mProvider == null);
857 mProvider = provider;
858
859 onUseableChangedLocked();
860 }
861
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700862 public String getName() {
863 return mName;
864 }
865
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800866 @GuardedBy("mLock")
867 @Nullable
868 public String getPackageLocked() {
869 if (mProvider == null) {
870 return null;
871 } else if (mProvider instanceof LocationProviderProxy) {
872 // safe to not clear binder context since this doesn't call into the actual provider
873 return ((LocationProviderProxy) mProvider).getConnectedPackageName();
874 } else {
875 return mContext.getPackageName();
876 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700877 }
878
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800879 public boolean isMock() {
880 return false;
881 }
882
883 @GuardedBy("mLock")
884 public boolean isPassiveLocked() {
885 return mProvider == mPassiveProvider;
886 }
887
888 @GuardedBy("mLock")
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700889 @Nullable
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800890 public ProviderProperties getPropertiesLocked() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700891 return mProperties;
892 }
893
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800894 @GuardedBy("mLock")
895 public void setRequestLocked(ProviderRequest request, WorkSource workSource) {
896 if (mProvider != null) {
897 long identity = Binder.clearCallingIdentity();
898 try {
899 mProvider.setRequest(request, workSource);
900 } finally {
901 Binder.restoreCallingIdentity(identity);
902 }
903 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700904 }
905
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800906 @GuardedBy("mLock")
907 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700908 pw.println(mName + " provider:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800909 if (isMock()) {
910 pw.println(" mock=true");
911 }
912 pw.println(" attached=" + (mProvider != null));
913 if (mIsManagedBySettings) {
914 pw.println(" allowed=" + mAllowed);
915 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700916 pw.println(" enabled=" + mEnabled);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800917 pw.println(" useable=" + mUseable);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700918 pw.println(" properties=" + mProperties);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800919
920 if (mProvider != null) {
921 long identity = Binder.clearCallingIdentity();
922 try {
923 mProvider.dump(fd, pw, args);
924 } finally {
925 Binder.restoreCallingIdentity(identity);
926 }
927 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700928 }
929
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800930 @GuardedBy("mLock")
931 public long getStatusUpdateTimeLocked() {
932 if (mProvider != null) {
933 long identity = Binder.clearCallingIdentity();
934 try {
935 return mProvider.getStatusUpdateTime();
936 } finally {
937 Binder.restoreCallingIdentity(identity);
938 }
939 } else {
940 return 0;
941 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700942 }
943
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800944 @GuardedBy("mLock")
945 public int getStatusLocked(Bundle extras) {
946 if (mProvider != null) {
947 long identity = Binder.clearCallingIdentity();
948 try {
949 return mProvider.getStatus(extras);
950 } finally {
951 Binder.restoreCallingIdentity(identity);
952 }
953 } else {
954 return AVAILABLE;
955 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700956 }
957
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800958 @GuardedBy("mLock")
959 public void sendExtraCommandLocked(String command, Bundle extras) {
960 if (mProvider != null) {
961 long identity = Binder.clearCallingIdentity();
962 try {
963 mProvider.sendExtraCommand(command, extras);
964 } finally {
965 Binder.restoreCallingIdentity(identity);
966 }
967 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700968 }
969
970 // called from any thread
971 @Override
972 public void onReportLocation(Location location) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800973 // no security check necessary because this is coming from an internal-only interface
974 // move calls coming from below LMS onto a different thread to avoid deadlock
975 runInternal(() -> {
976 synchronized (mLock) {
977 handleLocationChangedLocked(location, this);
978 }
979 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700980 }
981
982 // called from any thread
983 @Override
984 public void onReportLocation(List<Location> locations) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800985 // move calls coming from below LMS onto a different thread to avoid deadlock
986 runInternal(() -> {
987 synchronized (mLock) {
988 LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
989 if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
990 Slog.w(TAG, "reportLocationBatch() called without user permission");
991 return;
992 }
993
994 if (mGnssBatchingCallback == null) {
995 Slog.e(TAG, "reportLocationBatch() called without active Callback");
996 return;
997 }
998
999 try {
1000 mGnssBatchingCallback.onLocationBatch(locations);
1001 } catch (RemoteException e) {
1002 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1003 }
1004 }
1005 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001006 }
1007
1008 // called from any thread
1009 @Override
1010 public void onSetEnabled(boolean enabled) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001011 // move calls coming from below LMS onto a different thread to avoid deadlock
1012 runInternal(() -> {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001013 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001014 if (enabled == mEnabled) {
1015 return;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001016 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001017
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001018 mEnabled = enabled;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001019
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001020 // update provider allowed settings to reflect enabled status
1021 if (mIsManagedBySettings) {
1022 if (mEnabled && !mAllowed) {
1023 Settings.Secure.putStringForUser(
1024 mContext.getContentResolver(),
1025 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1026 "+" + mName,
1027 mCurrentUserId);
1028 } else if (!mEnabled && mAllowed) {
1029 Settings.Secure.putStringForUser(
1030 mContext.getContentResolver(),
1031 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1032 "-" + mName,
1033 mCurrentUserId);
1034 }
1035 }
1036
1037 onUseableChangedLocked();
1038 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001039 });
1040 }
1041
1042 @Override
1043 public void onSetProperties(ProviderProperties properties) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001044 // move calls coming from below LMS onto a different thread to avoid deadlock
1045 runInternal(() -> {
1046 synchronized (mLock) {
1047 mProperties = properties;
1048 }
1049 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001050 }
1051
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001052 @GuardedBy("mLock")
1053 public void onLocationModeChangedLocked() {
1054 onUseableChangedLocked();
1055 }
1056
1057 private boolean isAllowed() {
1058 return isAllowedForUser(mCurrentUserId);
1059 }
1060
1061 private boolean isAllowedForUser(int userId) {
1062 String allowedProviders = Settings.Secure.getStringForUser(
1063 mContext.getContentResolver(),
1064 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1065 userId);
1066 return TextUtils.delimitedStringContains(allowedProviders, ',', mName);
1067 }
1068
1069 @GuardedBy("mLock")
1070 public void onAllowedChangedLocked() {
1071 if (mIsManagedBySettings) {
1072 boolean allowed = isAllowed();
1073 if (allowed == mAllowed) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001074 return;
1075 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001076 mAllowed = allowed;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001077
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001078 // make a best effort to keep the setting matching the real enabled state of the
1079 // provider so that legacy applications aren't broken.
1080 if (mAllowed && !mEnabled) {
1081 Settings.Secure.putStringForUser(
1082 mContext.getContentResolver(),
1083 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1084 "-" + mName,
1085 mCurrentUserId);
1086 }
1087
1088 onUseableChangedLocked();
1089 }
1090 }
1091
1092 @GuardedBy("mLock")
1093 public boolean isUseableLocked() {
1094 return isUseableForUserLocked(mCurrentUserId);
1095 }
1096
1097 @GuardedBy("mLock")
1098 public boolean isUseableForUserLocked(int userId) {
1099 return userId == mCurrentUserId && mUseable;
1100 }
1101
1102 @GuardedBy("mLock")
1103 public void onUseableChangedLocked() {
1104 // if any property that contributes to "useability" here changes state, it MUST result
1105 // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
1106 // guarantee that it will always eventually reach the correct state.
1107 boolean useable = mProvider != null
1108 && mProviders.contains(this) && isLocationEnabled() && mAllowed && mEnabled;
1109 if (useable == mUseable) {
1110 return;
1111 }
1112 mUseable = useable;
1113
1114 if (!mUseable) {
1115 // If any provider has been disabled, clear all last locations for all
1116 // providers. This is to be on the safe side in case a provider has location
1117 // derived from this disabled provider.
1118 mLastLocation.clear();
1119 mLastLocationCoarseInterval.clear();
1120 }
1121
1122 updateProviderUseableLocked(this);
1123 }
1124
1125 @GuardedBy("mLock")
1126 public void onUserChangingLocked() {
1127 // when the user is about to change, we set this provider to un-useable, and notify all
1128 // of the current user clients. when the user is finished changing, useability will be
1129 // updated back via onLocationModeChanged() and onAllowedChanged().
1130 mUseable = false;
1131 updateProviderUseableLocked(this);
1132 }
1133
1134 // binder transactions coming from below LMS (ie location providers) need to be moved onto
1135 // a different thread to avoid potential deadlock as code reenters the location providers
1136 private void runInternal(Runnable runnable) {
1137 if (Looper.myLooper() == mHandler.getLooper()) {
1138 runnable.run();
1139 } else {
1140 mHandler.post(runnable);
1141 }
1142 }
1143 }
1144
1145 private class MockLocationProvider extends LocationProvider {
1146
1147 private MockLocationProvider(String name) {
1148 super(name);
1149 }
1150
1151 @Override
1152 public void attachLocked(AbstractLocationProvider provider) {
1153 checkState(provider instanceof MockProvider);
1154 super.attachLocked(provider);
1155 }
1156
1157 public boolean isMock() {
1158 return true;
1159 }
1160
1161 @GuardedBy("mLock")
1162 public void setEnabledLocked(boolean enabled) {
1163 if (mProvider != null) {
1164 long identity = Binder.clearCallingIdentity();
1165 try {
1166 ((MockProvider) mProvider).setEnabled(enabled);
1167 } finally {
1168 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00001169 }
1170 }
1171 }
1172
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001173 @GuardedBy("mLock")
1174 public void setLocationLocked(Location location) {
1175 if (mProvider != null) {
1176 long identity = Binder.clearCallingIdentity();
1177 try {
1178 ((MockProvider) mProvider).setLocation(location);
1179 } finally {
1180 Binder.restoreCallingIdentity(identity);
1181 }
1182 }
1183 }
1184
1185 @GuardedBy("mLock")
1186 public void setStatusLocked(int status, Bundle extras, long updateTime) {
1187 if (mProvider != null) {
1188 long identity = Binder.clearCallingIdentity();
1189 try {
1190 ((MockProvider) mProvider).setStatus(status, extras, updateTime);
1191 } finally {
1192 Binder.restoreCallingIdentity(identity);
1193 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001194 }
1195 }
1196 }
1197
Victoria Lease38389b62012-09-30 11:44:22 -07001198 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
1200 * location updates.
1201 */
Mike Lockwood48f17512009-04-23 09:12:08 -07001202 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -07001203 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001204 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001205 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001206
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001207 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -07001209 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001210 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
1211 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001212
gomo48f1a642017-11-10 20:35:46 -08001213 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -07001214
David Christie0b837452013-07-29 16:02:13 -07001215 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001216 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -07001217 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001218 private boolean mOpHighPowerMonitoring;
1219 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -07001220 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001222 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001223 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001226 if (listener != null) {
1227 mKey = listener.asBinder();
1228 } else {
1229 mKey = intent;
1230 }
Victoria Lease37425c32012-10-16 16:08:48 -07001231 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001232 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +00001233 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -07001234 workSource = null;
1235 }
1236 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -07001237 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -07001238
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001239 updateMonitoring(true);
1240
Victoria Lease0aa28602013-05-29 15:28:26 -07001241 // construct/configure wakelock
1242 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -07001243 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001244 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001245 }
1246 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -07001247
1248 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
1249 // only need to release it once.
1250 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 }
1252
1253 @Override
1254 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001255 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 }
1257
1258 @Override
1259 public int hashCode() {
1260 return mKey.hashCode();
1261 }
Mike Lockwood3681f262009-05-12 10:52:03 -04001262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 @Override
1264 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001265 StringBuilder s = new StringBuilder();
1266 s.append("Reciever[");
1267 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001269 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001271 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001273 for (String p : mUpdateRecords.keySet()) {
1274 s.append(" ").append(mUpdateRecords.get(p).toString());
1275 }
Wei Wangdd070f22018-06-21 11:29:40 -07001276 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001277 s.append("]");
1278 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 }
1280
David Christie15b31912013-08-13 15:54:32 -07001281 /**
1282 * Update AppOp monitoring for this receiver.
1283 *
1284 * @param allow If true receiver is currently active, if false it's been removed.
1285 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001286 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001287 if (mHideFromAppOps) {
1288 return;
1289 }
1290
David Christie15b31912013-08-13 15:54:32 -07001291 boolean requestingLocation = false;
1292 boolean requestingHighPowerLocation = false;
1293 if (allow) {
1294 // See if receiver has any enabled update records. Also note if any update records
1295 // are high power (has a high power provider with an interval under a threshold).
1296 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001297 LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
1298 if (provider == null || !provider.isUseableLocked()) {
1299 continue;
1300 }
1301
1302 requestingLocation = true;
1303 ProviderProperties properties = provider.getPropertiesLocked();
1304 if (properties != null
1305 && properties.mPowerRequirement == Criteria.POWER_HIGH
1306 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1307 requestingHighPowerLocation = true;
1308 break;
David Christie15b31912013-08-13 15:54:32 -07001309 }
1310 }
1311 }
1312
David Christie0b837452013-07-29 16:02:13 -07001313 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001314 mOpMonitoring = updateMonitoring(
1315 requestingLocation,
1316 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001317 AppOpsManager.OP_MONITOR_LOCATION);
1318
1319 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001320 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001321 mOpHighPowerMonitoring = updateMonitoring(
1322 requestingHighPowerLocation,
1323 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001324 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001325 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001326 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001327 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1328 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1329 }
David Christie0b837452013-07-29 16:02:13 -07001330 }
1331
1332 /**
1333 * Update AppOps monitoring for a single location request and op type.
1334 *
gomo48f1a642017-11-10 20:35:46 -08001335 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001336 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001337 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001338 * @return True if monitoring is on for this request/op after updating.
1339 */
1340 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1341 int op) {
1342 if (!currentlyMonitoring) {
1343 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001344 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001345 == AppOpsManager.MODE_ALLOWED;
1346 }
1347 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001348 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001349 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001350 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001351 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001352 return false;
1353 }
1354 }
1355
1356 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001357 }
1358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 public boolean isListener() {
1360 return mListener != null;
1361 }
1362
1363 public boolean isPendingIntent() {
1364 return mPendingIntent != null;
1365 }
1366
1367 public ILocationListener getListener() {
1368 if (mListener != null) {
1369 return mListener;
1370 }
1371 throw new IllegalStateException("Request for non-existent listener");
1372 }
1373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001374 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1375 if (mListener != null) {
1376 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001377 synchronized (this) {
1378 // synchronize to ensure incrementPendingBroadcastsLocked()
1379 // is called before decrementPendingBroadcasts()
1380 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001381 // call this after broadcasting so we do not increment
1382 // if we throw an exeption.
1383 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001384 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 } catch (RemoteException e) {
1386 return false;
1387 }
1388 } else {
1389 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001390 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1392 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001393 synchronized (this) {
1394 // synchronize to ensure incrementPendingBroadcastsLocked()
1395 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001396 mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001397 getResolutionPermission(mAllowedResolutionLevel),
1398 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001399 // call this after broadcasting so we do not increment
1400 // if we throw an exeption.
1401 incrementPendingBroadcastsLocked();
1402 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 } catch (PendingIntent.CanceledException e) {
1404 return false;
1405 }
1406 }
1407 return true;
1408 }
1409
1410 public boolean callLocationChangedLocked(Location location) {
1411 if (mListener != null) {
1412 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001413 synchronized (this) {
1414 // synchronize to ensure incrementPendingBroadcastsLocked()
1415 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001416 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001417 // call this after broadcasting so we do not increment
1418 // if we throw an exeption.
1419 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001420 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 } catch (RemoteException e) {
1422 return false;
1423 }
1424 } else {
1425 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001426 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1427 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001429 synchronized (this) {
1430 // synchronize to ensure incrementPendingBroadcastsLocked()
1431 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001432 mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001433 getResolutionPermission(mAllowedResolutionLevel),
1434 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001435 // call this after broadcasting so we do not increment
1436 // if we throw an exeption.
1437 incrementPendingBroadcastsLocked();
1438 }
1439 } catch (PendingIntent.CanceledException e) {
1440 return false;
1441 }
1442 }
1443 return true;
1444 }
1445
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001446 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001447 // First update AppOp monitoring.
1448 // An app may get/lose location access as providers are enabled/disabled.
1449 updateMonitoring(true);
1450
Mike Lockwood48f17512009-04-23 09:12:08 -07001451 if (mListener != null) {
1452 try {
1453 synchronized (this) {
1454 // synchronize to ensure incrementPendingBroadcastsLocked()
1455 // is called before decrementPendingBroadcasts()
1456 if (enabled) {
1457 mListener.onProviderEnabled(provider);
1458 } else {
1459 mListener.onProviderDisabled(provider);
1460 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001461 // call this after broadcasting so we do not increment
1462 // if we throw an exeption.
1463 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001464 }
1465 } catch (RemoteException e) {
1466 return false;
1467 }
1468 } else {
1469 Intent providerIntent = new Intent();
1470 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1471 try {
1472 synchronized (this) {
1473 // synchronize to ensure incrementPendingBroadcastsLocked()
1474 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001475 mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001476 getResolutionPermission(mAllowedResolutionLevel),
1477 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001478 // call this after broadcasting so we do not increment
1479 // if we throw an exeption.
1480 incrementPendingBroadcastsLocked();
1481 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001482 } catch (PendingIntent.CanceledException e) {
1483 return false;
1484 }
1485 }
1486 return true;
1487 }
1488
Nick Pellyf1be6862012-05-15 10:53:42 -07001489 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001491 if (D) Log.d(TAG, "Location listener died");
1492
Soonil Nagarkar68257742019-01-09 19:42:34 +00001493 synchronized (mLock) {
1494 removeUpdatesLocked(this);
1495 }
1496 synchronized (this) {
1497 clearPendingBroadcastsLocked();
1498 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001499 }
1500
Nick Pellye0fd6932012-07-11 10:26:13 -07001501 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001502 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1503 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001504 synchronized (this) {
1505 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001506 }
1507 }
1508
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001509 // this must be called while synchronized by caller in a synchronized block
1510 // containing the sending of the broadcaset
1511 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001512 mPendingBroadcasts++;
1513 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001514 }
1515
1516 private void decrementPendingBroadcastsLocked() {
1517 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001518 if (mWakeLock.isHeld()) {
1519 mWakeLock.release();
1520 }
1521 }
1522 }
1523
1524 public void clearPendingBroadcastsLocked() {
1525 if (mPendingBroadcasts > 0) {
1526 mPendingBroadcasts = 0;
1527 if (mWakeLock.isHeld()) {
1528 mWakeLock.release();
1529 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001530 }
1531 }
1532 }
1533
Nick Pellye0fd6932012-07-11 10:26:13 -07001534 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001535 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001536 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001537 //the receiver list if it is not found. If it is not found then the
1538 //LocationListener was removed when it had a pending broadcast and should
1539 //not be added back.
Soonil Nagarkar68257742019-01-09 19:42:34 +00001540 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001541 IBinder binder = listener.asBinder();
1542 Receiver receiver = mReceivers.get(binder);
1543 if (receiver != null) {
1544 synchronized (receiver) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001545 // so wakelock calls will succeed
1546 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001547 try {
1548 receiver.decrementPendingBroadcastsLocked();
1549 } finally {
1550 Binder.restoreCallingIdentity(identity);
1551 }
David Christie2ff96af2014-01-30 16:09:37 -08001552 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001553 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 }
1556
Lifu Tang82f893d2016-01-21 18:15:33 -08001557 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001558 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001559 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001560 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001561 } else {
1562 return 0;
1563 }
1564 }
1565
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001566 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001567 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001568 public String getGnssHardwareModelName() {
1569 if (mGnssSystemInfoProvider != null) {
1570 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1571 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001572 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001573 }
1574 }
1575
Wyatt Rileycf879db2017-01-12 13:57:38 -08001576 private boolean hasGnssPermissions(String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001577 synchronized (mLock) {
1578 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1579 checkResolutionLevelIsSufficientForProviderUseLocked(
1580 allowedResolutionLevel,
1581 GPS_PROVIDER);
Wyatt Rileycf879db2017-01-12 13:57:38 -08001582
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001583 int pid = Binder.getCallingPid();
1584 int uid = Binder.getCallingUid();
1585 long identity = Binder.clearCallingIdentity();
1586 try {
1587 return checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1588 } finally {
1589 Binder.restoreCallingIdentity(identity);
1590 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001591 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001592 }
1593
Wyatt Rileycf879db2017-01-12 13:57:38 -08001594 @Override
1595 public int getGnssBatchSize(String packageName) {
1596 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1597 "Location Hardware permission not granted to access hardware batching");
1598
1599 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001600 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001601 } else {
1602 return 0;
1603 }
1604 }
1605
Wyatt Rileycf879db2017-01-12 13:57:38 -08001606 @Override
1607 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1608 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1609 "Location Hardware permission not granted to access hardware batching");
1610
1611 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1612 return false;
1613 }
1614
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001615 synchronized (mLock) {
1616 mGnssBatchingCallback = callback;
1617 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1618 try {
1619 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1620 } catch (RemoteException e) {
1621 // if the remote process registering the listener is already dead, just swallow the
1622 // exception and return
1623 Log.e(TAG, "Remote listener already died.", e);
1624 return false;
1625 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001626
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001627 return true;
1628 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001629 }
1630
1631 private class LinkedCallback implements IBinder.DeathRecipient {
1632 private final IBatchedLocationCallback mCallback;
1633
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001634 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001635 mCallback = callback;
1636 }
1637
1638 @NonNull
1639 public IBatchedLocationCallback getUnderlyingListener() {
1640 return mCallback;
1641 }
1642
1643 @Override
1644 public void binderDied() {
1645 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1646 stopGnssBatch();
1647 removeGnssBatchingCallback();
1648 }
1649 }
1650
Wyatt Rileycf879db2017-01-12 13:57:38 -08001651 @Override
1652 public void removeGnssBatchingCallback() {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001653 synchronized (mLock) {
1654 try {
1655 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1656 0 /* flags */);
1657 } catch (NoSuchElementException e) {
1658 // if the death callback isn't connected (it should be...), log error, swallow the
1659 // exception and return
1660 Log.e(TAG, "Couldn't unlink death callback.", e);
1661 }
1662 mGnssBatchingCallback = null;
1663 mGnssBatchingDeathCallback = null;
Wyatt Rileycf879db2017-01-12 13:57:38 -08001664 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001665 }
1666
Wyatt Rileycf879db2017-01-12 13:57:38 -08001667 @Override
1668 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1669 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1670 "Location Hardware permission not granted to access hardware batching");
1671
1672 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1673 return false;
1674 }
1675
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001676 synchronized (mLock) {
1677 if (mGnssBatchingInProgress) {
1678 // Current design does not expect multiple starts to be called repeatedly
1679 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1680 // Try to clean up anyway, and continue
1681 stopGnssBatch();
1682 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001683
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001684 mGnssBatchingInProgress = true;
1685 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1686 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001687 }
1688
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001689
Wyatt Rileycf879db2017-01-12 13:57:38 -08001690 @Override
1691 public void flushGnssBatch(String packageName) {
1692 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1693 "Location Hardware permission not granted to access hardware batching");
1694
1695 if (!hasGnssPermissions(packageName)) {
1696 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1697 return;
1698 }
1699
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001700 synchronized (mLock) {
1701 if (!mGnssBatchingInProgress) {
1702 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1703 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001704
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001705 if (mGnssBatchingProvider != null) {
1706 mGnssBatchingProvider.flush();
1707 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001708 }
1709 }
1710
Wyatt Rileycf879db2017-01-12 13:57:38 -08001711 @Override
1712 public boolean stopGnssBatch() {
1713 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1714 "Location Hardware permission not granted to access hardware batching");
1715
Soonil Nagarkar68257742019-01-09 19:42:34 +00001716 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001717 if (mGnssBatchingProvider != null) {
1718 mGnssBatchingInProgress = false;
1719 return mGnssBatchingProvider.stop();
1720 } else {
1721 return false;
1722 }
1723 }
1724 }
1725
1726 @GuardedBy("mLock")
1727 private void addProviderLocked(LocationProvider provider) {
1728 Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
1729
1730 mProviders.add(provider);
1731
1732 provider.onAllowedChangedLocked(); // allowed state may change while provider was inactive
1733 provider.onUseableChangedLocked();
1734 }
1735
1736 @GuardedBy("mLock")
1737 private void removeProviderLocked(LocationProvider provider) {
1738 if (mProviders.remove(provider)) {
1739 long identity = Binder.clearCallingIdentity();
1740 try {
1741 provider.onUseableChangedLocked();
1742 } finally {
1743 Binder.restoreCallingIdentity(identity);
1744 }
1745 }
1746 }
1747
1748 @GuardedBy("mLock")
1749 @Nullable
1750 private LocationProvider getLocationProviderLocked(String providerName) {
1751 for (LocationProvider provider : mProviders) {
1752 if (providerName.equals(provider.getName())) {
1753 return provider;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001754 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001755 }
1756
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001757 return null;
Maggie2a9409e2018-03-21 11:47:28 -07001758 }
1759
Victoria Lease37425c32012-10-16 16:08:48 -07001760 private String getResolutionPermission(int resolutionLevel) {
1761 switch (resolutionLevel) {
1762 case RESOLUTION_LEVEL_FINE:
1763 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1764 case RESOLUTION_LEVEL_COARSE:
1765 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1766 default:
1767 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001769 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001770
Victoria Lease37425c32012-10-16 16:08:48 -07001771 private int getAllowedResolutionLevel(int pid, int uid) {
1772 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001773 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001774 return RESOLUTION_LEVEL_FINE;
1775 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001776 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001777 return RESOLUTION_LEVEL_COARSE;
1778 } else {
1779 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001780 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001781 }
1782
Victoria Lease37425c32012-10-16 16:08:48 -07001783 private int getCallerAllowedResolutionLevel() {
1784 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1785 }
1786
Victoria Lease37425c32012-10-16 16:08:48 -07001787 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1788 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001789 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 }
1792
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001793 @GuardedBy("mLock")
1794 private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
1795 if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001796 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001797 return RESOLUTION_LEVEL_FINE;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001798 } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001799 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001800 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001801 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001802 for (LocationProvider lp : mProviders) {
1803 if (!lp.getName().equals(provider)) {
1804 continue;
1805 }
1806
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001807 ProviderProperties properties = lp.getPropertiesLocked();
Laurent Tu941221c2012-10-04 14:21:52 -07001808 if (properties != null) {
1809 if (properties.mRequiresSatellite) {
1810 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001811 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001812 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1813 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001814 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001815 }
1816 }
1817 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001818 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001819
Victoria Lease37425c32012-10-16 16:08:48 -07001820 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001821 }
1822
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001823 @GuardedBy("mLock")
1824 private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001825 String providerName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001826 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
Victoria Lease37425c32012-10-16 16:08:48 -07001827 if (allowedResolutionLevel < requiredResolutionLevel) {
1828 switch (requiredResolutionLevel) {
1829 case RESOLUTION_LEVEL_FINE:
1830 throw new SecurityException("\"" + providerName + "\" location provider " +
1831 "requires ACCESS_FINE_LOCATION permission.");
1832 case RESOLUTION_LEVEL_COARSE:
1833 throw new SecurityException("\"" + providerName + "\" location provider " +
1834 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1835 default:
1836 throw new SecurityException("Insufficient permission for \"" + providerName +
1837 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001838 }
1839 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001840 }
1841
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001842 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001843 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1844 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001845 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001846 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001847 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001848 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001849 }
1850 return -1;
1851 }
1852
Wei Wangb86334f2018-07-03 16:33:24 -07001853 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001854 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001855 case RESOLUTION_LEVEL_COARSE:
1856 return AppOpsManager.OPSTR_COARSE_LOCATION;
1857 case RESOLUTION_LEVEL_FINE:
1858 return AppOpsManager.OPSTR_FINE_LOCATION;
1859 case RESOLUTION_LEVEL_NONE:
1860 // The client is not allowed to get any location, so both FINE and COARSE ops will
1861 // be denied. Pick the most restrictive one to be safe.
1862 return AppOpsManager.OPSTR_FINE_LOCATION;
1863 default:
1864 // Use the most restrictive ops if not sure.
1865 return AppOpsManager.OPSTR_FINE_LOCATION;
1866 }
1867 }
1868
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001869 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001870 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001871 int op = resolutionLevelToOp(allowedResolutionLevel);
1872 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001873 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1874 return false;
1875 }
1876 }
David Christieb870dbf2015-06-22 12:42:53 -07001877
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001878 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001879 }
1880
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001881 private boolean checkLocationAccess(int pid, int uid, String packageName,
1882 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001883 int op = resolutionLevelToOp(allowedResolutionLevel);
1884 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001885 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001886 return false;
1887 }
1888 }
David Christieb870dbf2015-06-22 12:42:53 -07001889
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001890 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001891 }
1892
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001893 /**
Maggie91e630c2018-01-24 17:31:46 -08001894 * Returns all providers by name, including passive and the ones that are not permitted to
1895 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001896 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001897 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 public List<String> getAllProviders() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001899 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001900 ArrayList<String> providers = new ArrayList<>(mProviders.size());
Soonil Nagarkar68257742019-01-09 19:42:34 +00001901 for (LocationProvider provider : mProviders) {
1902 String name = provider.getName();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001903 if (FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001904 continue;
1905 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001906 providers.add(name);
Maggie91e630c2018-01-24 17:31:46 -08001907 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001908 return providers;
Maggie91e630c2018-01-24 17:31:46 -08001909 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 }
1911
Mike Lockwood03ca2162010-04-01 08:10:09 -07001912 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001913 * Return all providers by name, that match criteria and are optionally
1914 * enabled.
1915 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001916 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001917 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001918 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001919 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001920 synchronized (mLock) {
1921 ArrayList<String> providers = new ArrayList<>(mProviders.size());
1922 for (LocationProvider provider : mProviders) {
1923 String name = provider.getName();
1924 if (FUSED_PROVIDER.equals(name)) {
1925 continue;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001926 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001927 if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
1928 continue;
1929 }
1930 if (enabledOnly && !provider.isUseableLocked()) {
1931 continue;
1932 }
1933 if (criteria != null
1934 && !android.location.LocationProvider.propertiesMeetCriteria(
1935 name, provider.getPropertiesLocked(), criteria)) {
1936 continue;
1937 }
1938 providers.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001939 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001940 return providers;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001941 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001942 }
1943
1944 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001945 * Return the name of the best provider given a Criteria object.
1946 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001947 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001948 * has been deprecated as well. So this method now uses
1949 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001950 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001951 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001952 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001953 List<String> providers = getProviders(criteria, enabledOnly);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001954 if (providers.isEmpty()) {
1955 providers = getProviders(null, enabledOnly);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001956 }
1957
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001958 if (!providers.isEmpty()) {
1959 if (providers.contains(GPS_PROVIDER)) {
1960 return GPS_PROVIDER;
1961 } else if (providers.contains(NETWORK_PROVIDER)) {
1962 return NETWORK_PROVIDER;
1963 } else {
1964 return providers.get(0);
1965 }
1966 }
1967
Mike Lockwood03ca2162010-04-01 08:10:09 -07001968 return null;
1969 }
1970
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001971 @GuardedBy("mLock")
1972 private void updateProviderUseableLocked(LocationProvider provider) {
1973 boolean useable = provider.isUseableLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001976
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001977 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001979 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001980 if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001981 // Sends a notification message to the receiver
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001982 if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001983 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001984 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001985 }
1986 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 }
1990 }
1991
1992 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001993 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001994 removeUpdatesLocked(deadReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001995 }
1996 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001997
Soonil Nagarkar68257742019-01-09 19:42:34 +00001998 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 }
2000
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002001 @GuardedBy("mLock")
2002 private void applyRequirementsLocked(String providerName) {
2003 LocationProvider provider = getLocationProviderLocked(providerName);
2004 if (provider != null) {
2005 applyRequirementsLocked(provider);
2006 }
2007 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002008
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002009 @GuardedBy("mLock")
2010 private void applyRequirementsLocked(LocationProvider provider) {
2011 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002012 WorkSource worksource = new WorkSource();
2013 ProviderRequest providerRequest = new ProviderRequest();
2014
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002015 long backgroundThrottleInterval;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002016
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002017 long identity = Binder.clearCallingIdentity();
2018 try {
2019 backgroundThrottleInterval = Settings.Global.getLong(
2020 mContext.getContentResolver(),
2021 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
2022 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
2023 } finally {
2024 Binder.restoreCallingIdentity(identity);
2025 }
2026
2027 if (provider.isUseableLocked() && records != null && !records.isEmpty()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002028 // initialize the low power mode to true and set to false if any of the records requires
2029 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002030 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002031 if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07002032 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002033 record.mReceiver.mIdentity.mPid,
2034 record.mReceiver.mIdentity.mUid,
2035 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002036 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002037 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002038 long interval = locationRequest.getInterval();
2039
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002040 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002041 if (!record.mIsForegroundUid) {
2042 interval = Math.max(interval, backgroundThrottleInterval);
2043 }
2044 if (interval != locationRequest.getInterval()) {
2045 locationRequest = new LocationRequest(locationRequest);
2046 locationRequest.setInterval(interval);
2047 }
2048 }
2049
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002050 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002051 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08002052 if (!locationRequest.isLowPowerMode()) {
2053 providerRequest.lowPowerMode = false;
2054 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002055 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002056 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002057 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002058 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002059 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002060 }
2061 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002062
2063 if (providerRequest.reportLocation) {
2064 // calculate who to blame for power
2065 // This is somewhat arbitrary. We pick a threshold interval
2066 // that is slightly higher that the minimum interval, and
2067 // spread the blame across all applications with a request
2068 // under that threshold.
2069 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
2070 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002071 if (isCurrentProfileLocked(
2072 UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002073 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07002074
2075 // Don't assign battery blame for update records whose
2076 // client has no permission to receive location data.
2077 if (!providerRequest.locationRequests.contains(locationRequest)) {
2078 continue;
2079 }
2080
Victoria Leaseb711d572012-10-02 13:14:11 -07002081 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07002082 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00002083 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07002084 worksource.add(record.mReceiver.mWorkSource);
2085 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00002086 // Assign blame to caller if there's no WorkSource associated with
2087 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07002088 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002089 record.mReceiver.mIdentity.mUid,
2090 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07002091 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002092 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002093 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002094 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002095 }
2096 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002097
2098 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002099 provider.setRequestLocked(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002100 }
2101
Narayan Kamath32684dd2018-01-08 17:32:51 +00002102 /**
2103 * Whether a given {@code WorkSource} associated with a Location request is valid.
2104 */
2105 private static boolean isValidWorkSource(WorkSource workSource) {
2106 if (workSource.size() > 0) {
2107 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
2108 // by tags.
2109 return workSource.getName(0) != null;
2110 } else {
2111 // For now, make sure callers have supplied an attribution tag for use with
2112 // AppOpsManager. This might be relaxed in the future.
2113 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
2114 return workChains != null && !workChains.isEmpty() &&
2115 workChains.get(0).getAttributionTag() != null;
2116 }
2117 }
2118
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002119 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002120 public String[] getBackgroundThrottlingWhitelist() {
2121 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002122 return mBackgroundThrottlePackageWhitelist.toArray(new String[0]);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002123 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002124 }
2125
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002126 @GuardedBy("mLock")
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002127 private boolean isThrottlingExemptLocked(Identity identity) {
2128 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002129 return true;
2130 }
2131
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002132 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002133 return true;
2134 }
2135
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002136 for (LocationProvider provider : mProviders) {
2137 if (identity.mPackageName.equals(provider.getPackageLocked())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002138 return true;
2139 }
2140 }
2141
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002142 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002143 }
2144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145 private class UpdateRecord {
2146 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002147 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002148 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002149 private final Receiver mReceiver;
2150 private boolean mIsForegroundUid;
2151 private Location mLastFixBroadcast;
2152 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002153
2154 /**
2155 * Note: must be constructed with lock held.
2156 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002157 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002158 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002159 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002160 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002162 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002163 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164
2165 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2166 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002167 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002168 mRecordsByProvider.put(provider, records);
2169 }
2170 if (!records.contains(this)) {
2171 records.add(this);
2172 }
David Christie2ff96af2014-01-30 16:09:37 -08002173
2174 // Update statistics for historical location requests by package/provider
2175 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002176 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2177 mIsForegroundUid);
2178 }
2179
2180 /**
2181 * Method to be called when record changes foreground/background
2182 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002183 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002184 mIsForegroundUid = isForeground;
2185 mRequestStatistics.updateForeground(
2186 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002187 }
2188
2189 /**
David Christie2ff96af2014-01-30 16:09:37 -08002190 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002191 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002192 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002193 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002194
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002195 // remove from mRecordsByProvider
2196 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2197 if (globalRecords != null) {
2198 globalRecords.remove(this);
2199 }
2200
2201 if (!removeReceiver) return; // the caller will handle the rest
2202
2203 // remove from Receiver#mUpdateRecords
2204 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002205 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002206
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002207 // and also remove the Receiver if it has no more update records
2208 if (receiverRecords.size() == 0) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002209 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002210 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211 }
2212
2213 @Override
2214 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002215 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002216 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2217 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002218 + ")" + " " + mRealRequest + " "
2219 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002221 }
2222
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002223 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002224 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002225 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002226 IBinder binder = listener.asBinder();
2227 Receiver receiver = mReceivers.get(binder);
2228 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002229 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2230 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002231 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002232 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002233 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002234 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002235 return null;
2236 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002237 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002238 }
2239 return receiver;
2240 }
2241
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002242 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002243 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002244 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002245 Receiver receiver = mReceivers.get(intent);
2246 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002247 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2248 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002249 mReceivers.put(intent, receiver);
2250 }
2251 return receiver;
2252 }
2253
Victoria Lease37425c32012-10-16 16:08:48 -07002254 /**
2255 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2256 * and consistency requirements.
2257 *
2258 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002259 * @return a version of request that meets the given resolution and consistency requirements
2260 * @hide
2261 */
gomo48f1a642017-11-10 20:35:46 -08002262 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2263 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002264 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002265 if (!callerHasLocationHardwarePermission) {
2266 // allow setting low power mode only for callers with location hardware permission
2267 sanitizedRequest.setLowPowerMode(false);
2268 }
Victoria Lease37425c32012-10-16 16:08:48 -07002269 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2270 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002271 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002272 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002273 break;
2274 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002275 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002276 break;
2277 }
2278 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002279 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2280 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002281 }
Victoria Lease37425c32012-10-16 16:08:48 -07002282 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2283 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002284 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002285 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002286 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002287 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002288 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002289 }
Victoria Lease37425c32012-10-16 16:08:48 -07002290 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002291 }
2292
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002293 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002294 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002295 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002296 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002297 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002298 String[] packages = mPackageManager.getPackagesForUid(uid);
2299 if (packages == null) {
2300 throw new SecurityException("invalid UID " + uid);
2301 }
2302 for (String pkg : packages) {
2303 if (packageName.equals(pkg)) return;
2304 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002305 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002306 }
2307
Nick Pellye0fd6932012-07-11 10:26:13 -07002308 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002309 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002310 PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002311 synchronized (mLock) {
2312 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2313 checkPackageName(packageName);
2314 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2315 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2316 request.getProvider());
2317 WorkSource workSource = request.getWorkSource();
2318 if (workSource != null && !workSource.isEmpty()) {
2319 mContext.enforceCallingOrSelfPermission(
2320 Manifest.permission.UPDATE_DEVICE_STATS, null);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002321 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002322 boolean hideFromAppOps = request.getHideFromAppOps();
2323 if (hideFromAppOps) {
2324 mContext.enforceCallingOrSelfPermission(
2325 Manifest.permission.UPDATE_APP_OPS_STATS, null);
2326 }
2327 boolean callerHasLocationHardwarePermission =
2328 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2329 == PERMISSION_GRANTED;
2330 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2331 allowedResolutionLevel,
2332 callerHasLocationHardwarePermission);
2333
2334 final int pid = Binder.getCallingPid();
2335 final int uid = Binder.getCallingUid();
2336
2337 long identity = Binder.clearCallingIdentity();
2338 try {
2339
2340 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2341 // a location.
2342 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
2343
2344 if (intent == null && listener == null) {
2345 throw new IllegalArgumentException("need either listener or intent");
2346 } else if (intent != null && listener != null) {
2347 throw new IllegalArgumentException(
2348 "cannot register both listener and intent");
2349 }
2350
2351 Receiver receiver;
2352 if (intent != null) {
2353 receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
2354 hideFromAppOps);
2355 } else {
2356 receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
2357 hideFromAppOps);
2358 }
2359 requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
2360 } finally {
2361 Binder.restoreCallingIdentity(identity);
2362 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002363 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002364 }
2365
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002366 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002367 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002368 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002369 // Figure out the provider. Either its explicitly request (legacy use cases), or
2370 // use the fused provider
2371 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2372 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002373 if (name == null) {
2374 throw new IllegalArgumentException("provider name must not be null");
2375 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002376
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002377 LocationProvider provider = getLocationProviderLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002378 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002379 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002380 }
2381
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002382 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002383 if (D) {
2384 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2385 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2386 + (record.mIsForegroundUid ? "foreground" : "background")
2387 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002388 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002389 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002390
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002391 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2392 if (oldRecord != null) {
2393 oldRecord.disposeLocked(false);
2394 }
2395
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002396 if (provider.isUseableLocked()) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002397 applyRequirementsLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002398 } else {
2399 // Notify the listener that updates are currently disabled
2400 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002401 }
David Christie0b837452013-07-29 16:02:13 -07002402 // Update the monitoring here just in case multiple location requests were added to the
2403 // same receiver (this request may be high power and the initial might not have been).
2404 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002405 }
2406
Nick Pellye0fd6932012-07-11 10:26:13 -07002407 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002408 public void removeUpdates(ILocationListener listener, PendingIntent intent,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002409 String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002410 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002411
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002412 int pid = Binder.getCallingPid();
2413 int uid = Binder.getCallingUid();
2414
2415 if (intent == null && listener == null) {
2416 throw new IllegalArgumentException("need either listener or intent");
2417 } else if (intent != null && listener != null) {
2418 throw new IllegalArgumentException("cannot register both listener and intent");
2419 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002420
Soonil Nagarkar68257742019-01-09 19:42:34 +00002421 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002422 Receiver receiver;
2423 if (intent != null) {
2424 receiver = getReceiverLocked(intent, pid, uid, packageName, null, false);
2425 } else {
2426 receiver = getReceiverLocked(listener, pid, uid, packageName, null, false);
2427 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002428
Soonil Nagarkar68257742019-01-09 19:42:34 +00002429 long identity = Binder.clearCallingIdentity();
2430 try {
2431 removeUpdatesLocked(receiver);
2432 } finally {
2433 Binder.restoreCallingIdentity(identity);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002434 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002436 }
2437
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002438 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002439 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002440 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002441
2442 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2443 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2444 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002445 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002446 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002447 }
2448
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002449 receiver.updateMonitoring(false);
2450
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002451 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002452 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002453 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2454 if (oldRecords != null) {
2455 // Call dispose() on the obsolete update records.
2456 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002457 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002458 record.disposeLocked(false);
2459 }
2460 // Accumulate providers
2461 providers.addAll(oldRecords.keySet());
2462 }
2463
2464 // update provider
2465 for (String provider : providers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002466 applyRequirementsLocked(provider);
2467 }
2468 }
2469
Nick Pellye0fd6932012-07-11 10:26:13 -07002470 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002471 public Location getLastLocation(LocationRequest r, String packageName) {
2472 if (D) Log.d(TAG, "getLastLocation: " + r);
2473 synchronized (mLock) {
2474 LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
2475 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2476 checkPackageName(packageName);
2477 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2478 request.getProvider());
2479 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002480
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002481 final int pid = Binder.getCallingPid();
2482 final int uid = Binder.getCallingUid();
2483 final long identity = Binder.clearCallingIdentity();
2484 try {
2485 if (mBlacklist.isBlacklisted(packageName)) {
2486 if (D) {
2487 Log.d(TAG, "not returning last loc for blacklisted app: "
2488 + packageName);
2489 }
2490 return null;
gomo48f1a642017-11-10 20:35:46 -08002491 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002492
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002493 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
2494 if (D) {
2495 Log.d(TAG, "not returning last loc for no op app: "
2496 + packageName);
2497 }
2498 return null;
gomo48f1a642017-11-10 20:35:46 -08002499 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002500
Soonil Nagarkar68257742019-01-09 19:42:34 +00002501 // Figure out the provider. Either its explicitly request (deprecated API's),
2502 // or use the fused provider
2503 String name = request.getProvider();
2504 if (name == null) name = LocationManager.FUSED_PROVIDER;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002505 LocationProvider provider = getLocationProviderLocked(name);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002506 if (provider == null) return null;
2507
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002508 // only the current user or location providers may get location this way
2509 if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isLocationProviderLocked(
2510 uid)) {
2511 return null;
2512 }
2513
2514 if (!provider.isUseableLocked()) {
2515 return null;
2516 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002517
2518 Location location;
2519 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2520 // Make sure that an app with coarse permissions can't get frequent location
2521 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2522 location = mLastLocationCoarseInterval.get(name);
2523 } else {
2524 location = mLastLocation.get(name);
2525 }
2526 if (location == null) {
2527 return null;
2528 }
2529
2530 // Don't return stale location to apps with foreground-only location permission.
2531 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002532 long locationAgeMs = SystemClock.elapsedRealtime()
2533 - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2534 if ((locationAgeMs > Settings.Global.getLong(
2535 mContext.getContentResolver(),
2536 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2537 DEFAULT_LAST_LOCATION_MAX_AGE_MS))
Soonil Nagarkar68257742019-01-09 19:42:34 +00002538 && (mAppOps.unsafeCheckOp(op, uid, packageName)
2539 == AppOpsManager.MODE_FOREGROUND)) {
2540 return null;
2541 }
2542
2543 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2544 Location noGPSLocation = location.getExtraLocation(
2545 Location.EXTRA_NO_GPS_LOCATION);
2546 if (noGPSLocation != null) {
2547 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
2548 }
2549 } else {
2550 return new Location(location);
2551 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002552 return null;
2553 } finally {
2554 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002555 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002556 }
2557 }
2558
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002559 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002560 public boolean injectLocation(Location location) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002561 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2562 "Location Hardware permission not granted to inject location");
2563 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2564 "Access Fine Location permission not granted to inject Location");
2565
2566 if (location == null) {
2567 if (D) {
2568 Log.d(TAG, "injectLocation(): called with null location");
2569 }
2570 return false;
2571 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002572
Soonil Nagarkar68257742019-01-09 19:42:34 +00002573 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002574 LocationProvider provider = getLocationProviderLocked(location.getProvider());
2575 if (provider == null || !provider.isUseableLocked()) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002576 return false;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002577 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002578
2579 // NOTE: If last location is already available, location is not injected. If
2580 // provider's normal source (like a GPS chipset) have already provided an output
2581 // there is no need to inject this location.
2582 if (mLastLocation.get(provider.getName()) != null) {
2583 return false;
2584 }
2585
2586 updateLastLocationLocked(location, provider.getName());
2587 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002588 }
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002589 }
2590
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002591 @Override
2592 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2593 String packageName) {
2594 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002595 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2596 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002597 if (intent == null) {
2598 throw new IllegalArgumentException("invalid pending intent: " + null);
Victoria Lease56e675b2012-11-05 19:25:06 -08002599 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002600 checkPackageName(packageName);
2601 synchronized (mLock) {
2602 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2603 request.getProvider());
2604 // Require that caller can manage given document
2605 boolean callerHasLocationHardwarePermission =
2606 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2607 == PERMISSION_GRANTED;
2608 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2609 allowedResolutionLevel,
2610 callerHasLocationHardwarePermission);
2611
2612 if (D) {
2613 Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
2614 }
2615
2616 // geo-fence manager uses the public location API, need to clear identity
2617 int uid = Binder.getCallingUid();
2618 // TODO: http://b/23822629
2619 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
2620 // temporary measure until geofences work for secondary users
2621 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2622 return;
2623 }
2624 long identity = Binder.clearCallingIdentity();
2625 try {
2626 mGeofenceManager.addFence(sanitizedRequest, geofence, intent,
2627 allowedResolutionLevel,
2628 uid, packageName);
2629 } finally {
2630 Binder.restoreCallingIdentity(identity);
2631 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002632 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002633 }
2634
2635 @Override
2636 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002637 if (intent == null) {
2638 throw new IllegalArgumentException("invalid pending intent: " + null);
2639 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002640 checkPackageName(packageName);
2641
2642 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2643
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002644 // geo-fence manager uses the public location API, need to clear identity
2645 long identity = Binder.clearCallingIdentity();
2646 try {
2647 mGeofenceManager.removeFence(geofence, intent);
2648 } finally {
2649 Binder.restoreCallingIdentity(identity);
2650 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002651 }
2652
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002653 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002654 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002655 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002656 return false;
2657 }
2658
Anil Admal75b9fd62018-11-28 11:22:50 -08002659 // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
2660 // measurements listeners.
2661 return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662 }
2663
Nick Pellye0fd6932012-07-11 10:26:13 -07002664 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002665 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002666 mGnssStatusProvider.removeListener(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002667 }
2668
Nick Pellye0fd6932012-07-11 10:26:13 -07002669 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002670 public boolean addGnssMeasurementsListener(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002671 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002672 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002673 return false;
2674 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002675
Soonil Nagarkar68257742019-01-09 19:42:34 +00002676 synchronized (mLock) {
2677 Identity callerIdentity
2678 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002679 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002680 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002681 long identity = Binder.clearCallingIdentity();
2682 try {
2683 if (isThrottlingExemptLocked(callerIdentity)
2684 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002685 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002686 return mGnssMeasurementsProvider.addListener(listener,
2687 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002688 }
2689 } finally {
2690 Binder.restoreCallingIdentity(identity);
2691 }
2692
2693 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002694 }
destradaaea8a8a62014-06-23 18:19:03 -07002695 }
2696
2697 @Override
gomo226b7b72018-12-12 16:49:39 -08002698 public void injectGnssMeasurementCorrections(
2699 GnssMeasurementCorrections measurementCorrections, String packageName) {
2700 mContext.enforceCallingPermission(
2701 android.Manifest.permission.LOCATION_HARDWARE,
2702 "Location Hardware permission not granted to inject GNSS measurement corrections.");
2703 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2704 mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
2705 } else {
2706 Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
2707 }
2708 }
2709
2710 @Override
2711 public int getGnssCapabilities(String packageName) {
2712 mContext.enforceCallingPermission(
2713 android.Manifest.permission.LOCATION_HARDWARE,
2714 "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
2715 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2716 return -1;
2717 }
2718 return mGnssMeasurementsProvider.getGnssCapabilities();
2719 }
2720
2721 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002722 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002723 if (mGnssMeasurementsProvider == null) {
2724 return;
2725 }
2726
Soonil Nagarkar68257742019-01-09 19:42:34 +00002727 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002728 mGnssMeasurementsListeners.remove(listener.asBinder());
2729 mGnssMeasurementsProvider.removeListener(listener);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002730 }
destradaaea8a8a62014-06-23 18:19:03 -07002731 }
2732
2733 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002734 public boolean addGnssNavigationMessageListener(
2735 IGnssNavigationMessageListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002736 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002737 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002738 return false;
2739 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002740
Soonil Nagarkar68257742019-01-09 19:42:34 +00002741 synchronized (mLock) {
2742 Identity callerIdentity
2743 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002744
Anil Admal75b9fd62018-11-28 11:22:50 -08002745 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002746 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002747 long identity = Binder.clearCallingIdentity();
2748 try {
2749 if (isThrottlingExemptLocked(callerIdentity)
2750 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002751 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002752 return mGnssNavigationMessageProvider.addListener(listener,
2753 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002754 }
2755 } finally {
2756 Binder.restoreCallingIdentity(identity);
2757 }
2758
2759 return true;
Wei Liu5241a4c2015-05-11 14:00:36 -07002760 }
destradaa4b3e3932014-07-21 18:01:47 -07002761 }
2762
2763 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002764 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2765 if (mGnssNavigationMessageProvider != null) {
2766 synchronized (mLock) {
2767 mGnssNavigationMessageListeners.remove(listener.asBinder());
2768 mGnssNavigationMessageProvider.removeListener(listener);
2769 }
2770 }
2771 }
2772
2773 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002774 public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
2775 if (providerName == null) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002776 // throw NullPointerException to remain compatible with previous implementation
2777 throw new NullPointerException();
2778 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002779 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002780 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2781 providerName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002782
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002783 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
2784 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
2785 != PERMISSION_GRANTED)) {
2786 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2787 }
2788
2789 LocationProvider provider = getLocationProviderLocked(providerName);
2790 if (provider != null) {
2791 provider.sendExtraCommandLocked(command, extras);
2792 }
2793
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002794 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002795 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002796 }
2797
Nick Pellye0fd6932012-07-11 10:26:13 -07002798 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002799 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002800 if (Binder.getCallingUid() != Process.myUid()) {
2801 throw new SecurityException(
2802 "calling sendNiResponse from outside of the system is not allowed");
2803 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002804 try {
2805 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002806 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002807 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002808 return false;
2809 }
2810 }
2811
Nick Pellye0fd6932012-07-11 10:26:13 -07002812 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002813 public ProviderProperties getProviderProperties(String providerName) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002814 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002815 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2816 providerName);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002817
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002818 LocationProvider provider = getLocationProviderLocked(providerName);
2819 if (provider == null) {
2820 return null;
2821 }
2822 return provider.getPropertiesLocked();
2823 }
Jason Monkb71218a2015-06-17 14:44:39 -04002824 }
2825
Wei Wang980b7c22018-12-06 17:53:00 -08002826 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002827 public String getNetworkProviderPackage() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002828 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002829 LocationProvider provider = getLocationProviderLocked(NETWORK_PROVIDER);
2830 if (provider == null) {
2831 return null;
2832 }
2833 return provider.getPackageLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +00002834 }
Maggie2a9409e2018-03-21 11:47:28 -07002835 }
2836
Maggie2a9409e2018-03-21 11:47:28 -07002837 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002838 public void setLocationControllerExtraPackage(String packageName) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002839 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2840 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002841 synchronized (mLock) {
2842 mLocationControllerExtraPackage = packageName;
2843 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002844 }
2845
2846 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002847 public String getLocationControllerExtraPackage() {
2848 synchronized (mLock) {
2849 return mLocationControllerExtraPackage;
2850 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002851 }
2852
2853 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002854 public void setLocationControllerExtraPackageEnabled(boolean enabled) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002855 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2856 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002857 synchronized (mLock) {
2858 mLocationControllerExtraPackageEnabled = enabled;
2859 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002860 }
2861
2862 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002863 public boolean isLocationControllerExtraPackageEnabled() {
2864 synchronized (mLock) {
2865 return mLocationControllerExtraPackageEnabled
2866 && (mLocationControllerExtraPackage != null);
2867 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002868 }
2869
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002870 private boolean isLocationEnabled() {
2871 return isLocationEnabledForUser(mCurrentUserId);
2872 }
2873
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002874 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002875 public boolean isLocationEnabledForUser(int userId) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002876 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002877 if (UserHandle.getCallingUserId() != userId) {
2878 mContext.enforceCallingOrSelfPermission(
2879 Manifest.permission.INTERACT_ACROSS_USERS,
2880 "Requires INTERACT_ACROSS_USERS permission");
2881 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002882
Soonil Nagarkar68257742019-01-09 19:42:34 +00002883 long identity = Binder.clearCallingIdentity();
2884 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002885 boolean enabled;
2886 try {
2887 enabled = Settings.Secure.getIntForUser(
2888 mContext.getContentResolver(),
2889 Settings.Secure.LOCATION_MODE,
2890 userId) != Settings.Secure.LOCATION_MODE_OFF;
2891 } catch (Settings.SettingNotFoundException e) {
2892 // OS upgrade case where mode isn't set yet
2893 enabled = !TextUtils.isEmpty(Settings.Secure.getStringForUser(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002894 mContext.getContentResolver(),
2895 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002896 userId));
2897
2898 try {
2899 Settings.Secure.putIntForUser(
2900 mContext.getContentResolver(),
2901 Settings.Secure.LOCATION_MODE,
2902 enabled
2903 ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
2904 : Settings.Secure.LOCATION_MODE_OFF,
2905 userId);
2906 } catch (RuntimeException ex) {
2907 // any problem with writing should not be propagated
2908 Slog.e(TAG, "error updating location mode", ex);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002909 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002910 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002911 return enabled;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002912 } finally {
2913 Binder.restoreCallingIdentity(identity);
2914 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002915 }
2916
Maggie2a9409e2018-03-21 11:47:28 -07002917 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002918 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002919 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002920 if (UserHandle.getCallingUserId() != userId) {
2921 mContext.enforceCallingOrSelfPermission(
2922 Manifest.permission.INTERACT_ACROSS_USERS,
2923 "Requires INTERACT_ACROSS_USERS permission");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002924 }
2925
Maggie2a9409e2018-03-21 11:47:28 -07002926 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2927 // so we discourage its use
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002928 if (FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002929
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002930 synchronized (mLock) {
2931 LocationProvider provider = getLocationProviderLocked(providerName);
2932 return provider != null && provider.isUseableForUserLocked(userId);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002933 }
Maggie2a9409e2018-03-21 11:47:28 -07002934 }
2935
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002936 @GuardedBy("mLock")
2937 private boolean isLocationProviderLocked(int uid) {
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002938 if (uid == Process.SYSTEM_UID) {
2939 return true;
2940 }
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002941
David Christie1f141c12014-05-14 15:11:15 -07002942 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2943 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002944 return false;
2945 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002946 for (LocationProvider provider : mProviders) {
2947 String packageName = provider.getPackageLocked();
2948 if (packageName == null) {
2949 continue;
2950 }
2951 if (ArrayUtils.contains(packageNames, packageName)) {
David Christie1f141c12014-05-14 15:11:15 -07002952 return true;
2953 }
2954 }
2955 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002956 }
2957
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002958 @GuardedBy("mLock")
2959 private static boolean shouldBroadcastSafeLocked(
Laurent Tu75defb62012-11-01 16:21:52 -07002960 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002961 // Always broadcast the first update
2962 if (lastLoc == null) {
2963 return true;
2964 }
2965
Nick Pellyf1be6862012-05-15 10:53:42 -07002966 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002967 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002968 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2969 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002970 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002971 return false;
2972 }
2973
2974 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002975 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002976 if (minDistance > 0.0) {
2977 if (loc.distanceTo(lastLoc) <= minDistance) {
2978 return false;
2979 }
2980 }
2981
Laurent Tu75defb62012-11-01 16:21:52 -07002982 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002983 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002984 return false;
2985 }
2986
2987 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002988 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002989 }
2990
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002991 @GuardedBy("mLock")
2992 private void handleLocationChangedLocked(Location location, LocationProvider provider) {
2993 if (!mProviders.contains(provider)) {
2994 return;
2995 }
2996 if (!location.isComplete()) {
2997 Log.w(TAG, "Dropping incomplete location: " + location);
2998 return;
2999 }
3000
3001 if (!provider.isPassiveLocked()) {
3002 // notify passive provider of the new location
3003 mPassiveProvider.updateLocation(location);
3004 }
3005
Soonil Nagarkar68257742019-01-09 19:42:34 +00003006 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003007 long now = SystemClock.elapsedRealtime();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003008 updateLastLocationLocked(location, provider.getName());
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003009 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003010 Location lastLocation = mLastLocation.get(provider.getName());
Mike Lockwood4e50b782009-04-03 08:24:43 -07003011 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003012 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
3013 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07003014 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003015
David Christie1b9b7b12013-04-15 15:31:11 -07003016 // Update last known coarse interval location if enough time has passed.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003017 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider.getName());
David Christie1b9b7b12013-04-15 15:31:11 -07003018 if (lastLocationCoarseInterval == null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003019 lastLocationCoarseInterval = new Location(location);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003020 mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
David Christie1b9b7b12013-04-15 15:31:11 -07003021 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003022 long timeDiffNanos = location.getElapsedRealtimeNanos()
David Christie1b9b7b12013-04-15 15:31:11 -07003023 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
3024 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003025 lastLocationCoarseInterval.set(location);
David Christie1b9b7b12013-04-15 15:31:11 -07003026 }
3027 // Don't ever return a coarse location that is more recent than the allowed update
3028 // interval (i.e. don't allow an app to keep registering and unregistering for
3029 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003030 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07003031 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3032
Laurent Tu60ec50a2012-10-04 17:00:10 -07003033 // Skip if there are no UpdateRecords for this provider.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003034 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Laurent Tu60ec50a2012-10-04 17:00:10 -07003035 if (records == null || records.size() == 0) return;
3036
Victoria Lease09016ab2012-09-16 12:33:15 -07003037 // Fetch coarse location
3038 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07003039 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003040 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
3041 }
3042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003043 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003044 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07003045
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003046 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003047 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003048 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003049 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003050
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003051 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003052 if (!isCurrentProfileLocked(receiverUserId)
3053 && !isLocationProviderLocked(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003054 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003055 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003056 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003057 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003058 }
3059 continue;
3060 }
3061
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003062 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003063 if (D) {
3064 Log.d(TAG, "skipping loc update for blacklisted app: " +
3065 receiver.mIdentity.mPackageName);
3066 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003067 continue;
3068 }
3069
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003070 if (!reportLocationAccessNoThrow(
3071 receiver.mIdentity.mPid,
3072 receiver.mIdentity.mUid,
3073 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003074 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003075 if (D) {
3076 Log.d(TAG, "skipping loc update for no op app: " +
3077 receiver.mIdentity.mPackageName);
3078 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003079 continue;
3080 }
3081
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003082 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003083 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3084 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003085 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07003086 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003087 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003088 if (notifyLocation != null) {
3089 Location lastLoc = r.mLastFixBroadcast;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003090 if ((lastLoc == null)
3091 || shouldBroadcastSafeLocked(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003092 if (lastLoc == null) {
3093 lastLoc = new Location(notifyLocation);
3094 r.mLastFixBroadcast = lastLoc;
3095 } else {
3096 lastLoc.set(notifyLocation);
3097 }
3098 if (!receiver.callLocationChangedLocked(notifyLocation)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003099 Slog.w(TAG, "RemoteException calling onLocationChanged on "
3100 + receiver);
Victoria Lease09016ab2012-09-16 12:33:15 -07003101 receiverDead = true;
3102 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003103 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003104 }
3105 }
3106
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003107 // TODO: location provider status callbacks have been disabled and deprecated, and are
3108 // guarded behind this setting now. should be removed completely post-Q
3109 if (Settings.Global.getInt(mContext.getContentResolver(),
3110 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003111 long newStatusUpdateTime = provider.getStatusUpdateTimeLocked();
3112 Bundle extras = new Bundle();
3113 int status = provider.getStatusLocked(extras);
3114
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003115 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3116 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003117 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003118
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003119 r.mLastStatusBroadcast = newStatusUpdateTime;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003120 if (!receiver.callStatusChangedLocked(provider.getName(), status, extras)) {
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003121 receiverDead = true;
3122 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3123 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003124 }
3125 }
3126
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003127 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003128 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003129 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003130 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003131 }
3132 deadUpdateRecords.add(r);
3133 }
3134 // track dead receivers
3135 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003136 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003137 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003138 }
3139 if (!deadReceivers.contains(receiver)) {
3140 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003141 }
3142 }
3143 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003144
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003145 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003146 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003147 for (Receiver receiver : deadReceivers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003148 removeUpdatesLocked(receiver);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003149 }
3150 }
3151 if (deadUpdateRecords != null) {
3152 for (UpdateRecord r : deadUpdateRecords) {
3153 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003154 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003155 applyRequirementsLocked(provider);
Victoria Lease8b38b292012-12-04 15:04:43 -08003156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 }
3158
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003159 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00003160 private void updateLastLocationLocked(Location location, String provider) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003161 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3162 Location lastNoGPSLocation;
3163 Location lastLocation = mLastLocation.get(provider);
3164 if (lastLocation == null) {
3165 lastLocation = new Location(provider);
3166 mLastLocation.put(provider, lastLocation);
3167 } else {
3168 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3169 if (noGPSLocation == null && lastNoGPSLocation != null) {
3170 // New location has no no-GPS location: adopt last no-GPS location. This is set
3171 // directly into location because we do not want to notify COARSE clients.
3172 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3173 }
3174 }
3175 lastLocation.set(location);
3176 }
3177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003178 // Geocoder
3179
Nick Pellye0fd6932012-07-11 10:26:13 -07003180 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003181 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003182 return mGeocodeProvider != null;
3183 }
3184
Nick Pellye0fd6932012-07-11 10:26:13 -07003185 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003186 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003187 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003188 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003189 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3190 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003191 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003192 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 }
3194
Mike Lockwooda55c3212009-04-15 11:10:11 -04003195
Nick Pellye0fd6932012-07-11 10:26:13 -07003196 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003197 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003198 double lowerLeftLatitude, double lowerLeftLongitude,
3199 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003200 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003201
3202 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003203 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3204 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3205 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003206 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003207 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 }
3209
3210 // Mock Providers
3211
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003212 private boolean canCallerAccessMockLocation(String opPackageName) {
3213 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3214 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003215 }
3216
Nick Pellye0fd6932012-07-11 10:26:13 -07003217 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003218 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003219 if (!canCallerAccessMockLocation(opPackageName)) {
3220 return;
3221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003222
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003223 if (PASSIVE_PROVIDER.equals(name)) {
Mike Lockwooda4903f22010-02-17 06:42:23 -05003224 throw new IllegalArgumentException("Cannot mock the passive location provider");
3225 }
3226
Soonil Nagarkar68257742019-01-09 19:42:34 +00003227 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003228 long identity = Binder.clearCallingIdentity();
3229 try {
3230 LocationProvider oldProvider = getLocationProviderLocked(name);
3231 if (oldProvider != null) {
3232 if (oldProvider.isMock()) {
3233 throw new IllegalArgumentException(
3234 "Provider \"" + name + "\" already exists");
3235 }
3236
3237 removeProviderLocked(oldProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003238 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003239
3240 MockLocationProvider mockProviderManager = new MockLocationProvider(name);
3241 addProviderLocked(mockProviderManager);
3242 mockProviderManager.attachLocked(new MockProvider(mockProviderManager, properties));
3243 } finally {
3244 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003245 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003246 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003247 }
3248
Nick Pellye0fd6932012-07-11 10:26:13 -07003249 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003250 public void removeTestProvider(String name, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003251 if (!canCallerAccessMockLocation(opPackageName)) {
3252 return;
3253 }
3254
Soonil Nagarkar68257742019-01-09 19:42:34 +00003255 synchronized (mLock) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003256 long identity = Binder.clearCallingIdentity();
3257 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003258 LocationProvider testProvider = getLocationProviderLocked(name);
3259 if (testProvider == null || !testProvider.isMock()) {
3260 throw new IllegalArgumentException("Provider \"" + name + "\" unknown");
3261 }
3262
3263 removeProviderLocked(testProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003264
Soonil Nagarkar68257742019-01-09 19:42:34 +00003265 // reinstate real provider if available
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003266 LocationProvider realProvider = null;
3267 for (LocationProvider provider : mRealProviders) {
3268 if (name.equals(provider.getName())) {
3269 realProvider = provider;
3270 break;
3271 }
3272 }
3273
Soonil Nagarkar68257742019-01-09 19:42:34 +00003274 if (realProvider != null) {
3275 addProviderLocked(realProvider);
3276 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003277 } finally {
3278 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003279 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003281 }
3282
Nick Pellye0fd6932012-07-11 10:26:13 -07003283 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003284 public void setTestProviderLocation(String providerName, Location location,
Soonil Nagarkar68257742019-01-09 19:42:34 +00003285 String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003286 if (!canCallerAccessMockLocation(opPackageName)) {
3287 return;
3288 }
3289
Soonil Nagarkar68257742019-01-09 19:42:34 +00003290 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003291 LocationProvider testProvider = getLocationProviderLocked(providerName);
3292 if (testProvider == null || !testProvider.isMock()) {
3293 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003294 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003295
3296 String locationProvider = location.getProvider();
3297 if (!TextUtils.isEmpty(locationProvider) && !providerName.equals(locationProvider)) {
3298 // The location has an explicit provider that is different from the mock
3299 // provider name. The caller may be trying to fool us via b/33091107.
3300 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3301 providerName + "!=" + location.getProvider());
3302 }
3303
3304 ((MockLocationProvider) testProvider).setLocationLocked(location);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003305 }
3306 }
3307
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003308 @Override
3309 public void setTestProviderEnabled(String providerName, boolean enabled, String opPackageName) {
3310 if (!canCallerAccessMockLocation(opPackageName)) {
3311 return;
3312 }
3313
3314 synchronized (mLock) {
3315 LocationProvider testProvider = getLocationProviderLocked(providerName);
3316 if (testProvider == null || !testProvider.isMock()) {
3317 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3318 }
3319
3320 ((MockLocationProvider) testProvider).setEnabledLocked(enabled);
3321 }
3322 }
3323
3324 @Override
3325 public void setTestProviderStatus(String providerName, int status, Bundle extras,
3326 long updateTime, String opPackageName) {
3327 if (!canCallerAccessMockLocation(opPackageName)) {
3328 return;
3329 }
3330
3331 synchronized (mLock) {
3332 LocationProvider testProvider = getLocationProviderLocked(providerName);
3333 if (testProvider == null || !testProvider.isMock()) {
3334 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3335 }
3336
3337 ((MockLocationProvider) testProvider).setStatusLocked(status, extras, updateTime);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003339 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003340
3341 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003342 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003343 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003344
Soonil Nagarkar68257742019-01-09 19:42:34 +00003345 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003346 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3347 if (mGnssMetricsProvider != null) {
3348 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3349 }
3350 return;
3351 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 pw.println("Current Location Manager state:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003353 pw.println(" Location Mode: " + isLocationEnabled());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003354 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003355 for (Receiver receiver : mReceivers.values()) {
3356 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003357 }
David Christie2ff96af2014-01-30 16:09:37 -08003358 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003359 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3360 pw.println(" " + entry.getKey() + ":");
3361 for (UpdateRecord record : entry.getValue()) {
3362 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003363 }
3364 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003365 pw.println(" Active GnssMeasurement Listeners:");
3366 for (Identity identity : mGnssMeasurementsListeners.values()) {
3367 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3368 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3369 }
3370 pw.println(" Active GnssNavigationMessage Listeners:");
3371 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3372 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3373 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3374 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003375 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003376 for (LocationProvider provider : mProviders) {
3377 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003378 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003379 + ((LocationProviderProxy) provider.mProvider)
3380 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003381 }
3382 }
David Christie2ff96af2014-01-30 16:09:37 -08003383 pw.println(" Historical Records by Provider:");
3384 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3385 : mRequestStatistics.statistics.entrySet()) {
3386 PackageProviderKey key = entry.getKey();
3387 PackageStatistics stats = entry.getValue();
3388 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3389 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003390 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003391 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3392 String provider = entry.getKey();
3393 Location location = entry.getValue();
3394 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003395 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003396
David Christie1b9b7b12013-04-15 15:31:11 -07003397 pw.println(" Last Known Locations Coarse Intervals:");
3398 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3399 String provider = entry.getKey();
3400 Location location = entry.getValue();
3401 pw.println(" " + provider + ": " + location);
3402 }
3403
Nick Pellye0fd6932012-07-11 10:26:13 -07003404 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003405
Nick Pelly4035f5a2012-08-17 14:43:49 -07003406 pw.append(" ");
3407 mBlacklist.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003408
Wei Wang980b7c22018-12-06 17:53:00 -08003409 if (mLocationControllerExtraPackage != null) {
3410 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
3411 + " enabled: " + mLocationControllerExtraPackageEnabled);
3412 }
3413
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003414 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3415 pw.println(" Throttling Whitelisted Packages:");
3416 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3417 pw.println(" " + packageName);
3418 }
3419 }
3420
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003421 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003422 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003423
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003424 if (args.length > 0 && "short".equals(args[0])) {
3425 return;
3426 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003427 for (LocationProvider provider : mProviders) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003428 provider.dumpLocked(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003429 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003430 if (mGnssBatchingInProgress) {
3431 pw.println(" GNSS batching in progress");
3432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 }
3434 }
3435}