blob: 312b83c56dea239e09a45c38a25c257a9be08adc [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 Nagarkar66c0bac2019-01-15 13:36:44 -08001044 // because this does not invoke any other methods which might result in calling back
1045 // into the location provider, it is safe to run this on the calling thread. it is also
1046 // currently necessary to run this on the calling thread to ensure that property changes
1047 // are publicly visibly immediately, ie for mock providers which are created.
1048 synchronized (mLock) {
1049 mProperties = properties;
1050 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001051 }
1052
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001053 @GuardedBy("mLock")
1054 public void onLocationModeChangedLocked() {
1055 onUseableChangedLocked();
1056 }
1057
1058 private boolean isAllowed() {
1059 return isAllowedForUser(mCurrentUserId);
1060 }
1061
1062 private boolean isAllowedForUser(int userId) {
1063 String allowedProviders = Settings.Secure.getStringForUser(
1064 mContext.getContentResolver(),
1065 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1066 userId);
1067 return TextUtils.delimitedStringContains(allowedProviders, ',', mName);
1068 }
1069
1070 @GuardedBy("mLock")
1071 public void onAllowedChangedLocked() {
1072 if (mIsManagedBySettings) {
1073 boolean allowed = isAllowed();
1074 if (allowed == mAllowed) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001075 return;
1076 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001077 mAllowed = allowed;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001078
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001079 // make a best effort to keep the setting matching the real enabled state of the
1080 // provider so that legacy applications aren't broken.
1081 if (mAllowed && !mEnabled) {
1082 Settings.Secure.putStringForUser(
1083 mContext.getContentResolver(),
1084 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1085 "-" + mName,
1086 mCurrentUserId);
1087 }
1088
1089 onUseableChangedLocked();
1090 }
1091 }
1092
1093 @GuardedBy("mLock")
1094 public boolean isUseableLocked() {
1095 return isUseableForUserLocked(mCurrentUserId);
1096 }
1097
1098 @GuardedBy("mLock")
1099 public boolean isUseableForUserLocked(int userId) {
1100 return userId == mCurrentUserId && mUseable;
1101 }
1102
1103 @GuardedBy("mLock")
1104 public void onUseableChangedLocked() {
1105 // if any property that contributes to "useability" here changes state, it MUST result
1106 // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
1107 // guarantee that it will always eventually reach the correct state.
1108 boolean useable = mProvider != null
1109 && mProviders.contains(this) && isLocationEnabled() && mAllowed && mEnabled;
1110 if (useable == mUseable) {
1111 return;
1112 }
1113 mUseable = useable;
1114
1115 if (!mUseable) {
1116 // If any provider has been disabled, clear all last locations for all
1117 // providers. This is to be on the safe side in case a provider has location
1118 // derived from this disabled provider.
1119 mLastLocation.clear();
1120 mLastLocationCoarseInterval.clear();
1121 }
1122
1123 updateProviderUseableLocked(this);
1124 }
1125
1126 @GuardedBy("mLock")
1127 public void onUserChangingLocked() {
1128 // when the user is about to change, we set this provider to un-useable, and notify all
1129 // of the current user clients. when the user is finished changing, useability will be
1130 // updated back via onLocationModeChanged() and onAllowedChanged().
1131 mUseable = false;
1132 updateProviderUseableLocked(this);
1133 }
1134
1135 // binder transactions coming from below LMS (ie location providers) need to be moved onto
1136 // a different thread to avoid potential deadlock as code reenters the location providers
1137 private void runInternal(Runnable runnable) {
1138 if (Looper.myLooper() == mHandler.getLooper()) {
1139 runnable.run();
1140 } else {
1141 mHandler.post(runnable);
1142 }
1143 }
1144 }
1145
1146 private class MockLocationProvider extends LocationProvider {
1147
1148 private MockLocationProvider(String name) {
1149 super(name);
1150 }
1151
1152 @Override
1153 public void attachLocked(AbstractLocationProvider provider) {
1154 checkState(provider instanceof MockProvider);
1155 super.attachLocked(provider);
1156 }
1157
1158 public boolean isMock() {
1159 return true;
1160 }
1161
1162 @GuardedBy("mLock")
1163 public void setEnabledLocked(boolean enabled) {
1164 if (mProvider != null) {
1165 long identity = Binder.clearCallingIdentity();
1166 try {
1167 ((MockProvider) mProvider).setEnabled(enabled);
1168 } finally {
1169 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00001170 }
1171 }
1172 }
1173
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001174 @GuardedBy("mLock")
1175 public void setLocationLocked(Location location) {
1176 if (mProvider != null) {
1177 long identity = Binder.clearCallingIdentity();
1178 try {
1179 ((MockProvider) mProvider).setLocation(location);
1180 } finally {
1181 Binder.restoreCallingIdentity(identity);
1182 }
1183 }
1184 }
1185
1186 @GuardedBy("mLock")
1187 public void setStatusLocked(int status, Bundle extras, long updateTime) {
1188 if (mProvider != null) {
1189 long identity = Binder.clearCallingIdentity();
1190 try {
1191 ((MockProvider) mProvider).setStatus(status, extras, updateTime);
1192 } finally {
1193 Binder.restoreCallingIdentity(identity);
1194 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001195 }
1196 }
1197 }
1198
Victoria Lease38389b62012-09-30 11:44:22 -07001199 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
1201 * location updates.
1202 */
Mike Lockwood48f17512009-04-23 09:12:08 -07001203 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -07001204 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001205 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001206 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001207
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001208 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001209 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -07001210 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001211 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
1212 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001213
gomo48f1a642017-11-10 20:35:46 -08001214 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -07001215
David Christie0b837452013-07-29 16:02:13 -07001216 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001217 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -07001218 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001219 private boolean mOpHighPowerMonitoring;
1220 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -07001221 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001223 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001224 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001227 if (listener != null) {
1228 mKey = listener.asBinder();
1229 } else {
1230 mKey = intent;
1231 }
Victoria Lease37425c32012-10-16 16:08:48 -07001232 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001233 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +00001234 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -07001235 workSource = null;
1236 }
1237 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -07001238 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -07001239
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001240 updateMonitoring(true);
1241
Victoria Lease0aa28602013-05-29 15:28:26 -07001242 // construct/configure wakelock
1243 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -07001244 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001245 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001246 }
1247 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -07001248
1249 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
1250 // only need to release it once.
1251 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 }
1253
1254 @Override
1255 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001256 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 }
1258
1259 @Override
1260 public int hashCode() {
1261 return mKey.hashCode();
1262 }
Mike Lockwood3681f262009-05-12 10:52:03 -04001263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 @Override
1265 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001266 StringBuilder s = new StringBuilder();
1267 s.append("Reciever[");
1268 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001270 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001272 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001274 for (String p : mUpdateRecords.keySet()) {
1275 s.append(" ").append(mUpdateRecords.get(p).toString());
1276 }
Wei Wangdd070f22018-06-21 11:29:40 -07001277 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001278 s.append("]");
1279 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 }
1281
David Christie15b31912013-08-13 15:54:32 -07001282 /**
1283 * Update AppOp monitoring for this receiver.
1284 *
1285 * @param allow If true receiver is currently active, if false it's been removed.
1286 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001287 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001288 if (mHideFromAppOps) {
1289 return;
1290 }
1291
David Christie15b31912013-08-13 15:54:32 -07001292 boolean requestingLocation = false;
1293 boolean requestingHighPowerLocation = false;
1294 if (allow) {
1295 // See if receiver has any enabled update records. Also note if any update records
1296 // are high power (has a high power provider with an interval under a threshold).
1297 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001298 LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
1299 if (provider == null || !provider.isUseableLocked()) {
1300 continue;
1301 }
1302
1303 requestingLocation = true;
1304 ProviderProperties properties = provider.getPropertiesLocked();
1305 if (properties != null
1306 && properties.mPowerRequirement == Criteria.POWER_HIGH
1307 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1308 requestingHighPowerLocation = true;
1309 break;
David Christie15b31912013-08-13 15:54:32 -07001310 }
1311 }
1312 }
1313
David Christie0b837452013-07-29 16:02:13 -07001314 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001315 mOpMonitoring = updateMonitoring(
1316 requestingLocation,
1317 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001318 AppOpsManager.OP_MONITOR_LOCATION);
1319
1320 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001321 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001322 mOpHighPowerMonitoring = updateMonitoring(
1323 requestingHighPowerLocation,
1324 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001325 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001326 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001327 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001328 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1329 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1330 }
David Christie0b837452013-07-29 16:02:13 -07001331 }
1332
1333 /**
1334 * Update AppOps monitoring for a single location request and op type.
1335 *
gomo48f1a642017-11-10 20:35:46 -08001336 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001337 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001338 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001339 * @return True if monitoring is on for this request/op after updating.
1340 */
1341 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1342 int op) {
1343 if (!currentlyMonitoring) {
1344 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001345 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001346 == AppOpsManager.MODE_ALLOWED;
1347 }
1348 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001349 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001350 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001351 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001352 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001353 return false;
1354 }
1355 }
1356
1357 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001358 }
1359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 public boolean isListener() {
1361 return mListener != null;
1362 }
1363
1364 public boolean isPendingIntent() {
1365 return mPendingIntent != null;
1366 }
1367
1368 public ILocationListener getListener() {
1369 if (mListener != null) {
1370 return mListener;
1371 }
1372 throw new IllegalStateException("Request for non-existent listener");
1373 }
1374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1376 if (mListener != null) {
1377 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001378 synchronized (this) {
1379 // synchronize to ensure incrementPendingBroadcastsLocked()
1380 // is called before decrementPendingBroadcasts()
1381 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001382 // call this after broadcasting so we do not increment
1383 // if we throw an exeption.
1384 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001385 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 } catch (RemoteException e) {
1387 return false;
1388 }
1389 } else {
1390 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001391 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1393 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001394 synchronized (this) {
1395 // synchronize to ensure incrementPendingBroadcastsLocked()
1396 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001397 mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001398 getResolutionPermission(mAllowedResolutionLevel),
1399 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001400 // call this after broadcasting so we do not increment
1401 // if we throw an exeption.
1402 incrementPendingBroadcastsLocked();
1403 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 } catch (PendingIntent.CanceledException e) {
1405 return false;
1406 }
1407 }
1408 return true;
1409 }
1410
1411 public boolean callLocationChangedLocked(Location location) {
1412 if (mListener != null) {
1413 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001414 synchronized (this) {
1415 // synchronize to ensure incrementPendingBroadcastsLocked()
1416 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001417 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001418 // call this after broadcasting so we do not increment
1419 // if we throw an exeption.
1420 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001421 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 } catch (RemoteException e) {
1423 return false;
1424 }
1425 } else {
1426 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001427 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1428 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001430 synchronized (this) {
1431 // synchronize to ensure incrementPendingBroadcastsLocked()
1432 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001433 mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001434 getResolutionPermission(mAllowedResolutionLevel),
1435 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001436 // call this after broadcasting so we do not increment
1437 // if we throw an exeption.
1438 incrementPendingBroadcastsLocked();
1439 }
1440 } catch (PendingIntent.CanceledException e) {
1441 return false;
1442 }
1443 }
1444 return true;
1445 }
1446
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001447 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001448 // First update AppOp monitoring.
1449 // An app may get/lose location access as providers are enabled/disabled.
1450 updateMonitoring(true);
1451
Mike Lockwood48f17512009-04-23 09:12:08 -07001452 if (mListener != null) {
1453 try {
1454 synchronized (this) {
1455 // synchronize to ensure incrementPendingBroadcastsLocked()
1456 // is called before decrementPendingBroadcasts()
1457 if (enabled) {
1458 mListener.onProviderEnabled(provider);
1459 } else {
1460 mListener.onProviderDisabled(provider);
1461 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001462 // call this after broadcasting so we do not increment
1463 // if we throw an exeption.
1464 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001465 }
1466 } catch (RemoteException e) {
1467 return false;
1468 }
1469 } else {
1470 Intent providerIntent = new Intent();
1471 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1472 try {
1473 synchronized (this) {
1474 // synchronize to ensure incrementPendingBroadcastsLocked()
1475 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001476 mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001477 getResolutionPermission(mAllowedResolutionLevel),
1478 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001479 // call this after broadcasting so we do not increment
1480 // if we throw an exeption.
1481 incrementPendingBroadcastsLocked();
1482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 } catch (PendingIntent.CanceledException e) {
1484 return false;
1485 }
1486 }
1487 return true;
1488 }
1489
Nick Pellyf1be6862012-05-15 10:53:42 -07001490 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001492 if (D) Log.d(TAG, "Location listener died");
1493
Soonil Nagarkar68257742019-01-09 19:42:34 +00001494 synchronized (mLock) {
1495 removeUpdatesLocked(this);
1496 }
1497 synchronized (this) {
1498 clearPendingBroadcastsLocked();
1499 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001500 }
1501
Nick Pellye0fd6932012-07-11 10:26:13 -07001502 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001503 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1504 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001505 synchronized (this) {
1506 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001507 }
1508 }
1509
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001510 // this must be called while synchronized by caller in a synchronized block
1511 // containing the sending of the broadcaset
1512 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001513 mPendingBroadcasts++;
1514 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001515 }
1516
1517 private void decrementPendingBroadcastsLocked() {
1518 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001519 if (mWakeLock.isHeld()) {
1520 mWakeLock.release();
1521 }
1522 }
1523 }
1524
1525 public void clearPendingBroadcastsLocked() {
1526 if (mPendingBroadcasts > 0) {
1527 mPendingBroadcasts = 0;
1528 if (mWakeLock.isHeld()) {
1529 mWakeLock.release();
1530 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001531 }
1532 }
1533 }
1534
Nick Pellye0fd6932012-07-11 10:26:13 -07001535 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001536 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001537 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001538 //the receiver list if it is not found. If it is not found then the
1539 //LocationListener was removed when it had a pending broadcast and should
1540 //not be added back.
Soonil Nagarkar68257742019-01-09 19:42:34 +00001541 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001542 IBinder binder = listener.asBinder();
1543 Receiver receiver = mReceivers.get(binder);
1544 if (receiver != null) {
1545 synchronized (receiver) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001546 // so wakelock calls will succeed
1547 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001548 try {
1549 receiver.decrementPendingBroadcastsLocked();
1550 } finally {
1551 Binder.restoreCallingIdentity(identity);
1552 }
David Christie2ff96af2014-01-30 16:09:37 -08001553 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001554 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 }
1557
Lifu Tang82f893d2016-01-21 18:15:33 -08001558 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001559 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001560 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001561 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001562 } else {
1563 return 0;
1564 }
1565 }
1566
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001567 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001568 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001569 public String getGnssHardwareModelName() {
1570 if (mGnssSystemInfoProvider != null) {
1571 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1572 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001573 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001574 }
1575 }
1576
Wyatt Rileycf879db2017-01-12 13:57:38 -08001577 private boolean hasGnssPermissions(String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001578 synchronized (mLock) {
1579 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1580 checkResolutionLevelIsSufficientForProviderUseLocked(
1581 allowedResolutionLevel,
1582 GPS_PROVIDER);
Wyatt Rileycf879db2017-01-12 13:57:38 -08001583
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001584 int pid = Binder.getCallingPid();
1585 int uid = Binder.getCallingUid();
1586 long identity = Binder.clearCallingIdentity();
1587 try {
1588 return checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1589 } finally {
1590 Binder.restoreCallingIdentity(identity);
1591 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001592 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001593 }
1594
Wyatt Rileycf879db2017-01-12 13:57:38 -08001595 @Override
1596 public int getGnssBatchSize(String packageName) {
1597 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1598 "Location Hardware permission not granted to access hardware batching");
1599
1600 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001601 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001602 } else {
1603 return 0;
1604 }
1605 }
1606
Wyatt Rileycf879db2017-01-12 13:57:38 -08001607 @Override
1608 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1609 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1610 "Location Hardware permission not granted to access hardware batching");
1611
1612 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1613 return false;
1614 }
1615
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001616 synchronized (mLock) {
1617 mGnssBatchingCallback = callback;
1618 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1619 try {
1620 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1621 } catch (RemoteException e) {
1622 // if the remote process registering the listener is already dead, just swallow the
1623 // exception and return
1624 Log.e(TAG, "Remote listener already died.", e);
1625 return false;
1626 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001627
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001628 return true;
1629 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001630 }
1631
1632 private class LinkedCallback implements IBinder.DeathRecipient {
1633 private final IBatchedLocationCallback mCallback;
1634
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001635 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001636 mCallback = callback;
1637 }
1638
1639 @NonNull
1640 public IBatchedLocationCallback getUnderlyingListener() {
1641 return mCallback;
1642 }
1643
1644 @Override
1645 public void binderDied() {
1646 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1647 stopGnssBatch();
1648 removeGnssBatchingCallback();
1649 }
1650 }
1651
Wyatt Rileycf879db2017-01-12 13:57:38 -08001652 @Override
1653 public void removeGnssBatchingCallback() {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001654 synchronized (mLock) {
1655 try {
1656 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1657 0 /* flags */);
1658 } catch (NoSuchElementException e) {
1659 // if the death callback isn't connected (it should be...), log error, swallow the
1660 // exception and return
1661 Log.e(TAG, "Couldn't unlink death callback.", e);
1662 }
1663 mGnssBatchingCallback = null;
1664 mGnssBatchingDeathCallback = null;
Wyatt Rileycf879db2017-01-12 13:57:38 -08001665 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001666 }
1667
Wyatt Rileycf879db2017-01-12 13:57:38 -08001668 @Override
1669 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1670 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1671 "Location Hardware permission not granted to access hardware batching");
1672
1673 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1674 return false;
1675 }
1676
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001677 synchronized (mLock) {
1678 if (mGnssBatchingInProgress) {
1679 // Current design does not expect multiple starts to be called repeatedly
1680 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1681 // Try to clean up anyway, and continue
1682 stopGnssBatch();
1683 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001684
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001685 mGnssBatchingInProgress = true;
1686 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1687 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001688 }
1689
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001690
Wyatt Rileycf879db2017-01-12 13:57:38 -08001691 @Override
1692 public void flushGnssBatch(String packageName) {
1693 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1694 "Location Hardware permission not granted to access hardware batching");
1695
1696 if (!hasGnssPermissions(packageName)) {
1697 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1698 return;
1699 }
1700
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001701 synchronized (mLock) {
1702 if (!mGnssBatchingInProgress) {
1703 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1704 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001705
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001706 if (mGnssBatchingProvider != null) {
1707 mGnssBatchingProvider.flush();
1708 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001709 }
1710 }
1711
Wyatt Rileycf879db2017-01-12 13:57:38 -08001712 @Override
1713 public boolean stopGnssBatch() {
1714 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1715 "Location Hardware permission not granted to access hardware batching");
1716
Soonil Nagarkar68257742019-01-09 19:42:34 +00001717 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001718 if (mGnssBatchingProvider != null) {
1719 mGnssBatchingInProgress = false;
1720 return mGnssBatchingProvider.stop();
1721 } else {
1722 return false;
1723 }
1724 }
1725 }
1726
1727 @GuardedBy("mLock")
1728 private void addProviderLocked(LocationProvider provider) {
1729 Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
1730
1731 mProviders.add(provider);
1732
1733 provider.onAllowedChangedLocked(); // allowed state may change while provider was inactive
1734 provider.onUseableChangedLocked();
1735 }
1736
1737 @GuardedBy("mLock")
1738 private void removeProviderLocked(LocationProvider provider) {
1739 if (mProviders.remove(provider)) {
1740 long identity = Binder.clearCallingIdentity();
1741 try {
1742 provider.onUseableChangedLocked();
1743 } finally {
1744 Binder.restoreCallingIdentity(identity);
1745 }
1746 }
1747 }
1748
1749 @GuardedBy("mLock")
1750 @Nullable
1751 private LocationProvider getLocationProviderLocked(String providerName) {
1752 for (LocationProvider provider : mProviders) {
1753 if (providerName.equals(provider.getName())) {
1754 return provider;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001755 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001756 }
1757
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001758 return null;
Maggie2a9409e2018-03-21 11:47:28 -07001759 }
1760
Victoria Lease37425c32012-10-16 16:08:48 -07001761 private String getResolutionPermission(int resolutionLevel) {
1762 switch (resolutionLevel) {
1763 case RESOLUTION_LEVEL_FINE:
1764 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1765 case RESOLUTION_LEVEL_COARSE:
1766 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1767 default:
1768 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001770 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001771
Victoria Lease37425c32012-10-16 16:08:48 -07001772 private int getAllowedResolutionLevel(int pid, int uid) {
1773 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001774 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001775 return RESOLUTION_LEVEL_FINE;
1776 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001777 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001778 return RESOLUTION_LEVEL_COARSE;
1779 } else {
1780 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001781 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001782 }
1783
Victoria Lease37425c32012-10-16 16:08:48 -07001784 private int getCallerAllowedResolutionLevel() {
1785 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1786 }
1787
Victoria Lease37425c32012-10-16 16:08:48 -07001788 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1789 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001790 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1791 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 }
1793
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001794 @GuardedBy("mLock")
1795 private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
1796 if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001797 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001798 return RESOLUTION_LEVEL_FINE;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001799 } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001800 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001801 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001802 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001803 for (LocationProvider lp : mProviders) {
1804 if (!lp.getName().equals(provider)) {
1805 continue;
1806 }
1807
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001808 ProviderProperties properties = lp.getPropertiesLocked();
Laurent Tu941221c2012-10-04 14:21:52 -07001809 if (properties != null) {
1810 if (properties.mRequiresSatellite) {
1811 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001812 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001813 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1814 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001815 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001816 }
1817 }
1818 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001819 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001820
Victoria Lease37425c32012-10-16 16:08:48 -07001821 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001822 }
1823
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001824 @GuardedBy("mLock")
1825 private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001826 String providerName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001827 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
Victoria Lease37425c32012-10-16 16:08:48 -07001828 if (allowedResolutionLevel < requiredResolutionLevel) {
1829 switch (requiredResolutionLevel) {
1830 case RESOLUTION_LEVEL_FINE:
1831 throw new SecurityException("\"" + providerName + "\" location provider " +
1832 "requires ACCESS_FINE_LOCATION permission.");
1833 case RESOLUTION_LEVEL_COARSE:
1834 throw new SecurityException("\"" + providerName + "\" location provider " +
1835 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1836 default:
1837 throw new SecurityException("Insufficient permission for \"" + providerName +
1838 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001839 }
1840 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001841 }
1842
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001843 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001844 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1845 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001846 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001847 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001848 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001849 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001850 }
1851 return -1;
1852 }
1853
Wei Wangb86334f2018-07-03 16:33:24 -07001854 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001855 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001856 case RESOLUTION_LEVEL_COARSE:
1857 return AppOpsManager.OPSTR_COARSE_LOCATION;
1858 case RESOLUTION_LEVEL_FINE:
1859 return AppOpsManager.OPSTR_FINE_LOCATION;
1860 case RESOLUTION_LEVEL_NONE:
1861 // The client is not allowed to get any location, so both FINE and COARSE ops will
1862 // be denied. Pick the most restrictive one to be safe.
1863 return AppOpsManager.OPSTR_FINE_LOCATION;
1864 default:
1865 // Use the most restrictive ops if not sure.
1866 return AppOpsManager.OPSTR_FINE_LOCATION;
1867 }
1868 }
1869
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001870 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001871 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001872 int op = resolutionLevelToOp(allowedResolutionLevel);
1873 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001874 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1875 return false;
1876 }
1877 }
David Christieb870dbf2015-06-22 12:42:53 -07001878
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001879 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001880 }
1881
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001882 private boolean checkLocationAccess(int pid, int uid, String packageName,
1883 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001884 int op = resolutionLevelToOp(allowedResolutionLevel);
1885 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001886 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001887 return false;
1888 }
1889 }
David Christieb870dbf2015-06-22 12:42:53 -07001890
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001891 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001892 }
1893
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001894 /**
Maggie91e630c2018-01-24 17:31:46 -08001895 * Returns all providers by name, including passive and the ones that are not permitted to
1896 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001897 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001898 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 public List<String> getAllProviders() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001900 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001901 ArrayList<String> providers = new ArrayList<>(mProviders.size());
Soonil Nagarkar68257742019-01-09 19:42:34 +00001902 for (LocationProvider provider : mProviders) {
1903 String name = provider.getName();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001904 if (FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001905 continue;
1906 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001907 providers.add(name);
Maggie91e630c2018-01-24 17:31:46 -08001908 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001909 return providers;
Maggie91e630c2018-01-24 17:31:46 -08001910 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 }
1912
Mike Lockwood03ca2162010-04-01 08:10:09 -07001913 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001914 * Return all providers by name, that match criteria and are optionally
1915 * enabled.
1916 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001917 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001918 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001919 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001920 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001921 synchronized (mLock) {
1922 ArrayList<String> providers = new ArrayList<>(mProviders.size());
1923 for (LocationProvider provider : mProviders) {
1924 String name = provider.getName();
1925 if (FUSED_PROVIDER.equals(name)) {
1926 continue;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001927 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001928 if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
1929 continue;
1930 }
1931 if (enabledOnly && !provider.isUseableLocked()) {
1932 continue;
1933 }
1934 if (criteria != null
1935 && !android.location.LocationProvider.propertiesMeetCriteria(
1936 name, provider.getPropertiesLocked(), criteria)) {
1937 continue;
1938 }
1939 providers.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001940 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001941 return providers;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001942 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001943 }
1944
1945 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001946 * Return the name of the best provider given a Criteria object.
1947 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001948 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001949 * has been deprecated as well. So this method now uses
1950 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001951 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001952 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001953 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001954 List<String> providers = getProviders(criteria, enabledOnly);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001955 if (providers.isEmpty()) {
1956 providers = getProviders(null, enabledOnly);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001957 }
1958
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001959 if (!providers.isEmpty()) {
1960 if (providers.contains(GPS_PROVIDER)) {
1961 return GPS_PROVIDER;
1962 } else if (providers.contains(NETWORK_PROVIDER)) {
1963 return NETWORK_PROVIDER;
1964 } else {
1965 return providers.get(0);
1966 }
1967 }
1968
Mike Lockwood03ca2162010-04-01 08:10:09 -07001969 return null;
1970 }
1971
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001972 @GuardedBy("mLock")
1973 private void updateProviderUseableLocked(LocationProvider provider) {
1974 boolean useable = provider.isUseableLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001977
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001978 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001980 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001981 if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001982 // Sends a notification message to the receiver
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001983 if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001984 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001985 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001986 }
1987 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 }
1991 }
1992
1993 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001994 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001995 removeUpdatesLocked(deadReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 }
1997 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001998
Soonil Nagarkar68257742019-01-09 19:42:34 +00001999 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
2001
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002002 @GuardedBy("mLock")
2003 private void applyRequirementsLocked(String providerName) {
2004 LocationProvider provider = getLocationProviderLocked(providerName);
2005 if (provider != null) {
2006 applyRequirementsLocked(provider);
2007 }
2008 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002009
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002010 @GuardedBy("mLock")
2011 private void applyRequirementsLocked(LocationProvider provider) {
2012 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002013 WorkSource worksource = new WorkSource();
2014 ProviderRequest providerRequest = new ProviderRequest();
2015
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002016 long backgroundThrottleInterval;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002017
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002018 long identity = Binder.clearCallingIdentity();
2019 try {
2020 backgroundThrottleInterval = Settings.Global.getLong(
2021 mContext.getContentResolver(),
2022 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
2023 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
2024 } finally {
2025 Binder.restoreCallingIdentity(identity);
2026 }
2027
2028 if (provider.isUseableLocked() && records != null && !records.isEmpty()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002029 // initialize the low power mode to true and set to false if any of the records requires
2030 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002031 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002032 if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07002033 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002034 record.mReceiver.mIdentity.mPid,
2035 record.mReceiver.mIdentity.mUid,
2036 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002037 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002038 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002039 long interval = locationRequest.getInterval();
2040
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002041 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002042 if (!record.mIsForegroundUid) {
2043 interval = Math.max(interval, backgroundThrottleInterval);
2044 }
2045 if (interval != locationRequest.getInterval()) {
2046 locationRequest = new LocationRequest(locationRequest);
2047 locationRequest.setInterval(interval);
2048 }
2049 }
2050
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002051 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002052 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08002053 if (!locationRequest.isLowPowerMode()) {
2054 providerRequest.lowPowerMode = false;
2055 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002056 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002057 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002058 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002059 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002060 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002061 }
2062 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002063
2064 if (providerRequest.reportLocation) {
2065 // calculate who to blame for power
2066 // This is somewhat arbitrary. We pick a threshold interval
2067 // that is slightly higher that the minimum interval, and
2068 // spread the blame across all applications with a request
2069 // under that threshold.
2070 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
2071 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002072 if (isCurrentProfileLocked(
2073 UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002074 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07002075
2076 // Don't assign battery blame for update records whose
2077 // client has no permission to receive location data.
2078 if (!providerRequest.locationRequests.contains(locationRequest)) {
2079 continue;
2080 }
2081
Victoria Leaseb711d572012-10-02 13:14:11 -07002082 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07002083 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00002084 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07002085 worksource.add(record.mReceiver.mWorkSource);
2086 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00002087 // Assign blame to caller if there's no WorkSource associated with
2088 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07002089 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002090 record.mReceiver.mIdentity.mUid,
2091 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07002092 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002093 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002094 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002095 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002096 }
2097 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002098
2099 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002100 provider.setRequestLocked(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002101 }
2102
Narayan Kamath32684dd2018-01-08 17:32:51 +00002103 /**
2104 * Whether a given {@code WorkSource} associated with a Location request is valid.
2105 */
2106 private static boolean isValidWorkSource(WorkSource workSource) {
2107 if (workSource.size() > 0) {
2108 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
2109 // by tags.
2110 return workSource.getName(0) != null;
2111 } else {
2112 // For now, make sure callers have supplied an attribution tag for use with
2113 // AppOpsManager. This might be relaxed in the future.
2114 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
2115 return workChains != null && !workChains.isEmpty() &&
2116 workChains.get(0).getAttributionTag() != null;
2117 }
2118 }
2119
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002120 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002121 public String[] getBackgroundThrottlingWhitelist() {
2122 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002123 return mBackgroundThrottlePackageWhitelist.toArray(new String[0]);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002124 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002125 }
2126
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002127 @GuardedBy("mLock")
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002128 private boolean isThrottlingExemptLocked(Identity identity) {
2129 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002130 return true;
2131 }
2132
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002133 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002134 return true;
2135 }
2136
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002137 for (LocationProvider provider : mProviders) {
2138 if (identity.mPackageName.equals(provider.getPackageLocked())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002139 return true;
2140 }
2141 }
2142
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002143 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002144 }
2145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002146 private class UpdateRecord {
2147 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002148 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002149 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002150 private final Receiver mReceiver;
2151 private boolean mIsForegroundUid;
2152 private Location mLastFixBroadcast;
2153 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002154
2155 /**
2156 * Note: must be constructed with lock held.
2157 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002158 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002159 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002160 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002161 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002162 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002163 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002164 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002165
2166 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2167 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002168 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002169 mRecordsByProvider.put(provider, records);
2170 }
2171 if (!records.contains(this)) {
2172 records.add(this);
2173 }
David Christie2ff96af2014-01-30 16:09:37 -08002174
2175 // Update statistics for historical location requests by package/provider
2176 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002177 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2178 mIsForegroundUid);
2179 }
2180
2181 /**
2182 * Method to be called when record changes foreground/background
2183 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002184 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002185 mIsForegroundUid = isForeground;
2186 mRequestStatistics.updateForeground(
2187 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 }
2189
2190 /**
David Christie2ff96af2014-01-30 16:09:37 -08002191 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002192 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002193 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002194 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002195
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002196 // remove from mRecordsByProvider
2197 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2198 if (globalRecords != null) {
2199 globalRecords.remove(this);
2200 }
2201
2202 if (!removeReceiver) return; // the caller will handle the rest
2203
2204 // remove from Receiver#mUpdateRecords
2205 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002206 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002207
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002208 // and also remove the Receiver if it has no more update records
2209 if (receiverRecords.size() == 0) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002210 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002211 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212 }
2213
2214 @Override
2215 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002216 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002217 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2218 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002219 + ")" + " " + mRealRequest + " "
2220 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 }
2223
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002224 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002225 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002226 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002227 IBinder binder = listener.asBinder();
2228 Receiver receiver = mReceivers.get(binder);
2229 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002230 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2231 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002232 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002233 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002234 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002235 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002236 return null;
2237 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002238 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002239 }
2240 return receiver;
2241 }
2242
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002243 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002244 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002245 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002246 Receiver receiver = mReceivers.get(intent);
2247 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002248 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2249 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002250 mReceivers.put(intent, receiver);
2251 }
2252 return receiver;
2253 }
2254
Victoria Lease37425c32012-10-16 16:08:48 -07002255 /**
2256 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2257 * and consistency requirements.
2258 *
2259 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002260 * @return a version of request that meets the given resolution and consistency requirements
2261 * @hide
2262 */
gomo48f1a642017-11-10 20:35:46 -08002263 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2264 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002265 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002266 if (!callerHasLocationHardwarePermission) {
2267 // allow setting low power mode only for callers with location hardware permission
2268 sanitizedRequest.setLowPowerMode(false);
2269 }
Victoria Lease37425c32012-10-16 16:08:48 -07002270 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2271 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002272 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002273 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002274 break;
2275 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002276 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002277 break;
2278 }
2279 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002280 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2281 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002282 }
Victoria Lease37425c32012-10-16 16:08:48 -07002283 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2284 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002285 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002286 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002287 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002288 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002289 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002290 }
Victoria Lease37425c32012-10-16 16:08:48 -07002291 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002292 }
2293
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002294 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002295 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002296 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002297 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002298 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002299 String[] packages = mPackageManager.getPackagesForUid(uid);
2300 if (packages == null) {
2301 throw new SecurityException("invalid UID " + uid);
2302 }
2303 for (String pkg : packages) {
2304 if (packageName.equals(pkg)) return;
2305 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002306 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002307 }
2308
Nick Pellye0fd6932012-07-11 10:26:13 -07002309 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002310 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002311 PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002312 synchronized (mLock) {
2313 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2314 checkPackageName(packageName);
2315 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2316 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2317 request.getProvider());
2318 WorkSource workSource = request.getWorkSource();
2319 if (workSource != null && !workSource.isEmpty()) {
2320 mContext.enforceCallingOrSelfPermission(
2321 Manifest.permission.UPDATE_DEVICE_STATS, null);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002322 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002323 boolean hideFromAppOps = request.getHideFromAppOps();
2324 if (hideFromAppOps) {
2325 mContext.enforceCallingOrSelfPermission(
2326 Manifest.permission.UPDATE_APP_OPS_STATS, null);
2327 }
2328 boolean callerHasLocationHardwarePermission =
2329 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2330 == PERMISSION_GRANTED;
2331 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2332 allowedResolutionLevel,
2333 callerHasLocationHardwarePermission);
2334
2335 final int pid = Binder.getCallingPid();
2336 final int uid = Binder.getCallingUid();
2337
2338 long identity = Binder.clearCallingIdentity();
2339 try {
2340
2341 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2342 // a location.
2343 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
2344
2345 if (intent == null && listener == null) {
2346 throw new IllegalArgumentException("need either listener or intent");
2347 } else if (intent != null && listener != null) {
2348 throw new IllegalArgumentException(
2349 "cannot register both listener and intent");
2350 }
2351
2352 Receiver receiver;
2353 if (intent != null) {
2354 receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
2355 hideFromAppOps);
2356 } else {
2357 receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
2358 hideFromAppOps);
2359 }
2360 requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
2361 } finally {
2362 Binder.restoreCallingIdentity(identity);
2363 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002365 }
2366
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002367 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002368 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002369 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002370 // Figure out the provider. Either its explicitly request (legacy use cases), or
2371 // use the fused provider
2372 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2373 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002374 if (name == null) {
2375 throw new IllegalArgumentException("provider name must not be null");
2376 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002377
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002378 LocationProvider provider = getLocationProviderLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002379 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002380 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002381 }
2382
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002383 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002384 if (D) {
2385 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2386 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2387 + (record.mIsForegroundUid ? "foreground" : "background")
2388 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002389 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002390 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002391
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002392 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2393 if (oldRecord != null) {
2394 oldRecord.disposeLocked(false);
2395 }
2396
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002397 if (provider.isUseableLocked()) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002398 applyRequirementsLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002399 } else {
2400 // Notify the listener that updates are currently disabled
2401 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002402 }
David Christie0b837452013-07-29 16:02:13 -07002403 // Update the monitoring here just in case multiple location requests were added to the
2404 // same receiver (this request may be high power and the initial might not have been).
2405 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002406 }
2407
Nick Pellye0fd6932012-07-11 10:26:13 -07002408 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002409 public void removeUpdates(ILocationListener listener, PendingIntent intent,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002410 String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002411 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002412
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002413 int pid = Binder.getCallingPid();
2414 int uid = Binder.getCallingUid();
2415
2416 if (intent == null && listener == null) {
2417 throw new IllegalArgumentException("need either listener or intent");
2418 } else if (intent != null && listener != null) {
2419 throw new IllegalArgumentException("cannot register both listener and intent");
2420 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002421
Soonil Nagarkar68257742019-01-09 19:42:34 +00002422 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002423 Receiver receiver;
2424 if (intent != null) {
2425 receiver = getReceiverLocked(intent, pid, uid, packageName, null, false);
2426 } else {
2427 receiver = getReceiverLocked(listener, pid, uid, packageName, null, false);
2428 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002429
Soonil Nagarkar68257742019-01-09 19:42:34 +00002430 long identity = Binder.clearCallingIdentity();
2431 try {
2432 removeUpdatesLocked(receiver);
2433 } finally {
2434 Binder.restoreCallingIdentity(identity);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002435 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002436 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002437 }
2438
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002439 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002440 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002441 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002442
2443 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2444 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2445 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002446 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002447 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002448 }
2449
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002450 receiver.updateMonitoring(false);
2451
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002452 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002453 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002454 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2455 if (oldRecords != null) {
2456 // Call dispose() on the obsolete update records.
2457 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002458 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002459 record.disposeLocked(false);
2460 }
2461 // Accumulate providers
2462 providers.addAll(oldRecords.keySet());
2463 }
2464
2465 // update provider
2466 for (String provider : providers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002467 applyRequirementsLocked(provider);
2468 }
2469 }
2470
Nick Pellye0fd6932012-07-11 10:26:13 -07002471 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002472 public Location getLastLocation(LocationRequest r, String packageName) {
2473 if (D) Log.d(TAG, "getLastLocation: " + r);
2474 synchronized (mLock) {
2475 LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
2476 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2477 checkPackageName(packageName);
2478 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2479 request.getProvider());
2480 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002481
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002482 final int pid = Binder.getCallingPid();
2483 final int uid = Binder.getCallingUid();
2484 final long identity = Binder.clearCallingIdentity();
2485 try {
2486 if (mBlacklist.isBlacklisted(packageName)) {
2487 if (D) {
2488 Log.d(TAG, "not returning last loc for blacklisted app: "
2489 + packageName);
2490 }
2491 return null;
gomo48f1a642017-11-10 20:35:46 -08002492 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002493
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002494 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
2495 if (D) {
2496 Log.d(TAG, "not returning last loc for no op app: "
2497 + packageName);
2498 }
2499 return null;
gomo48f1a642017-11-10 20:35:46 -08002500 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002501
Soonil Nagarkar68257742019-01-09 19:42:34 +00002502 // Figure out the provider. Either its explicitly request (deprecated API's),
2503 // or use the fused provider
2504 String name = request.getProvider();
2505 if (name == null) name = LocationManager.FUSED_PROVIDER;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002506 LocationProvider provider = getLocationProviderLocked(name);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002507 if (provider == null) return null;
2508
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002509 // only the current user or location providers may get location this way
2510 if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isLocationProviderLocked(
2511 uid)) {
2512 return null;
2513 }
2514
2515 if (!provider.isUseableLocked()) {
2516 return null;
2517 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002518
2519 Location location;
2520 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2521 // Make sure that an app with coarse permissions can't get frequent location
2522 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2523 location = mLastLocationCoarseInterval.get(name);
2524 } else {
2525 location = mLastLocation.get(name);
2526 }
2527 if (location == null) {
2528 return null;
2529 }
2530
2531 // Don't return stale location to apps with foreground-only location permission.
2532 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002533 long locationAgeMs = SystemClock.elapsedRealtime()
2534 - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2535 if ((locationAgeMs > Settings.Global.getLong(
2536 mContext.getContentResolver(),
2537 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2538 DEFAULT_LAST_LOCATION_MAX_AGE_MS))
Soonil Nagarkar68257742019-01-09 19:42:34 +00002539 && (mAppOps.unsafeCheckOp(op, uid, packageName)
2540 == AppOpsManager.MODE_FOREGROUND)) {
2541 return null;
2542 }
2543
2544 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2545 Location noGPSLocation = location.getExtraLocation(
2546 Location.EXTRA_NO_GPS_LOCATION);
2547 if (noGPSLocation != null) {
2548 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
2549 }
2550 } else {
2551 return new Location(location);
2552 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002553 return null;
2554 } finally {
2555 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002556 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002557 }
2558 }
2559
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002560 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002561 public boolean injectLocation(Location location) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002562 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2563 "Location Hardware permission not granted to inject location");
2564 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2565 "Access Fine Location permission not granted to inject Location");
2566
2567 if (location == null) {
2568 if (D) {
2569 Log.d(TAG, "injectLocation(): called with null location");
2570 }
2571 return false;
2572 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002573
Soonil Nagarkar68257742019-01-09 19:42:34 +00002574 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002575 LocationProvider provider = getLocationProviderLocked(location.getProvider());
2576 if (provider == null || !provider.isUseableLocked()) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002577 return false;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002578 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002579
2580 // NOTE: If last location is already available, location is not injected. If
2581 // provider's normal source (like a GPS chipset) have already provided an output
2582 // there is no need to inject this location.
2583 if (mLastLocation.get(provider.getName()) != null) {
2584 return false;
2585 }
2586
2587 updateLastLocationLocked(location, provider.getName());
2588 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002589 }
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002590 }
2591
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002592 @Override
2593 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2594 String packageName) {
2595 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002596 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2597 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002598 if (intent == null) {
2599 throw new IllegalArgumentException("invalid pending intent: " + null);
Victoria Lease56e675b2012-11-05 19:25:06 -08002600 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002601 checkPackageName(packageName);
2602 synchronized (mLock) {
2603 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2604 request.getProvider());
2605 // Require that caller can manage given document
2606 boolean callerHasLocationHardwarePermission =
2607 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2608 == PERMISSION_GRANTED;
2609 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2610 allowedResolutionLevel,
2611 callerHasLocationHardwarePermission);
2612
2613 if (D) {
2614 Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
2615 }
2616
2617 // geo-fence manager uses the public location API, need to clear identity
2618 int uid = Binder.getCallingUid();
2619 // TODO: http://b/23822629
2620 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
2621 // temporary measure until geofences work for secondary users
2622 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2623 return;
2624 }
2625 long identity = Binder.clearCallingIdentity();
2626 try {
2627 mGeofenceManager.addFence(sanitizedRequest, geofence, intent,
2628 allowedResolutionLevel,
2629 uid, packageName);
2630 } finally {
2631 Binder.restoreCallingIdentity(identity);
2632 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002633 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002634 }
2635
2636 @Override
2637 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002638 if (intent == null) {
2639 throw new IllegalArgumentException("invalid pending intent: " + null);
2640 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002641 checkPackageName(packageName);
2642
2643 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2644
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002645 // geo-fence manager uses the public location API, need to clear identity
2646 long identity = Binder.clearCallingIdentity();
2647 try {
2648 mGeofenceManager.removeFence(geofence, intent);
2649 } finally {
2650 Binder.restoreCallingIdentity(identity);
2651 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002652 }
2653
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002654 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002655 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002656 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002657 return false;
2658 }
2659
Anil Admal75b9fd62018-11-28 11:22:50 -08002660 // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
2661 // measurements listeners.
2662 return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002663 }
2664
Nick Pellye0fd6932012-07-11 10:26:13 -07002665 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002666 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002667 mGnssStatusProvider.removeListener(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002668 }
2669
Nick Pellye0fd6932012-07-11 10:26:13 -07002670 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002671 public boolean addGnssMeasurementsListener(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002672 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002673 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002674 return false;
2675 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002676
Soonil Nagarkar68257742019-01-09 19:42:34 +00002677 synchronized (mLock) {
2678 Identity callerIdentity
2679 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002680 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002681 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002682 long identity = Binder.clearCallingIdentity();
2683 try {
2684 if (isThrottlingExemptLocked(callerIdentity)
2685 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002686 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002687 return mGnssMeasurementsProvider.addListener(listener,
2688 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002689 }
2690 } finally {
2691 Binder.restoreCallingIdentity(identity);
2692 }
2693
2694 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002695 }
destradaaea8a8a62014-06-23 18:19:03 -07002696 }
2697
2698 @Override
gomo226b7b72018-12-12 16:49:39 -08002699 public void injectGnssMeasurementCorrections(
2700 GnssMeasurementCorrections measurementCorrections, String packageName) {
2701 mContext.enforceCallingPermission(
2702 android.Manifest.permission.LOCATION_HARDWARE,
2703 "Location Hardware permission not granted to inject GNSS measurement corrections.");
2704 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2705 mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
2706 } else {
2707 Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
2708 }
2709 }
2710
2711 @Override
2712 public int getGnssCapabilities(String packageName) {
2713 mContext.enforceCallingPermission(
2714 android.Manifest.permission.LOCATION_HARDWARE,
2715 "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
2716 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2717 return -1;
2718 }
2719 return mGnssMeasurementsProvider.getGnssCapabilities();
2720 }
2721
2722 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002723 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002724 if (mGnssMeasurementsProvider == null) {
2725 return;
2726 }
2727
Soonil Nagarkar68257742019-01-09 19:42:34 +00002728 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002729 mGnssMeasurementsListeners.remove(listener.asBinder());
2730 mGnssMeasurementsProvider.removeListener(listener);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002731 }
destradaaea8a8a62014-06-23 18:19:03 -07002732 }
2733
2734 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002735 public boolean addGnssNavigationMessageListener(
2736 IGnssNavigationMessageListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002737 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002738 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002739 return false;
2740 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002741
Soonil Nagarkar68257742019-01-09 19:42:34 +00002742 synchronized (mLock) {
2743 Identity callerIdentity
2744 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002745
Anil Admal75b9fd62018-11-28 11:22:50 -08002746 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002747 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002748 long identity = Binder.clearCallingIdentity();
2749 try {
2750 if (isThrottlingExemptLocked(callerIdentity)
2751 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002752 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002753 return mGnssNavigationMessageProvider.addListener(listener,
2754 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002755 }
2756 } finally {
2757 Binder.restoreCallingIdentity(identity);
2758 }
2759
2760 return true;
Wei Liu5241a4c2015-05-11 14:00:36 -07002761 }
destradaa4b3e3932014-07-21 18:01:47 -07002762 }
2763
2764 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002765 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2766 if (mGnssNavigationMessageProvider != null) {
2767 synchronized (mLock) {
2768 mGnssNavigationMessageListeners.remove(listener.asBinder());
2769 mGnssNavigationMessageProvider.removeListener(listener);
2770 }
2771 }
2772 }
2773
2774 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002775 public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
2776 if (providerName == null) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002777 // throw NullPointerException to remain compatible with previous implementation
2778 throw new NullPointerException();
2779 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002780 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002781 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2782 providerName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002783
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002784 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
2785 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
2786 != PERMISSION_GRANTED)) {
2787 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2788 }
2789
2790 LocationProvider provider = getLocationProviderLocked(providerName);
2791 if (provider != null) {
2792 provider.sendExtraCommandLocked(command, extras);
2793 }
2794
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002795 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002796 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002797 }
2798
Nick Pellye0fd6932012-07-11 10:26:13 -07002799 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002800 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002801 if (Binder.getCallingUid() != Process.myUid()) {
2802 throw new SecurityException(
2803 "calling sendNiResponse from outside of the system is not allowed");
2804 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002805 try {
2806 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002807 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002808 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002809 return false;
2810 }
2811 }
2812
Nick Pellye0fd6932012-07-11 10:26:13 -07002813 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002814 public ProviderProperties getProviderProperties(String providerName) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002815 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002816 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2817 providerName);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002818
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002819 LocationProvider provider = getLocationProviderLocked(providerName);
2820 if (provider == null) {
2821 return null;
2822 }
2823 return provider.getPropertiesLocked();
2824 }
Jason Monkb71218a2015-06-17 14:44:39 -04002825 }
2826
Wei Wang980b7c22018-12-06 17:53:00 -08002827 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002828 public String getNetworkProviderPackage() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002829 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002830 LocationProvider provider = getLocationProviderLocked(NETWORK_PROVIDER);
2831 if (provider == null) {
2832 return null;
2833 }
2834 return provider.getPackageLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +00002835 }
Maggie2a9409e2018-03-21 11:47:28 -07002836 }
2837
Maggie2a9409e2018-03-21 11:47:28 -07002838 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002839 public void setLocationControllerExtraPackage(String packageName) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002840 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2841 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002842 synchronized (mLock) {
2843 mLocationControllerExtraPackage = packageName;
2844 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002845 }
2846
2847 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002848 public String getLocationControllerExtraPackage() {
2849 synchronized (mLock) {
2850 return mLocationControllerExtraPackage;
2851 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002852 }
2853
2854 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002855 public void setLocationControllerExtraPackageEnabled(boolean enabled) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002856 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2857 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002858 synchronized (mLock) {
2859 mLocationControllerExtraPackageEnabled = enabled;
2860 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002861 }
2862
2863 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002864 public boolean isLocationControllerExtraPackageEnabled() {
2865 synchronized (mLock) {
2866 return mLocationControllerExtraPackageEnabled
2867 && (mLocationControllerExtraPackage != null);
2868 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002869 }
2870
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002871 private boolean isLocationEnabled() {
2872 return isLocationEnabledForUser(mCurrentUserId);
2873 }
2874
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002875 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002876 public boolean isLocationEnabledForUser(int userId) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002877 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002878 if (UserHandle.getCallingUserId() != userId) {
2879 mContext.enforceCallingOrSelfPermission(
2880 Manifest.permission.INTERACT_ACROSS_USERS,
2881 "Requires INTERACT_ACROSS_USERS permission");
2882 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002883
Soonil Nagarkar68257742019-01-09 19:42:34 +00002884 long identity = Binder.clearCallingIdentity();
2885 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002886 boolean enabled;
2887 try {
2888 enabled = Settings.Secure.getIntForUser(
2889 mContext.getContentResolver(),
2890 Settings.Secure.LOCATION_MODE,
2891 userId) != Settings.Secure.LOCATION_MODE_OFF;
2892 } catch (Settings.SettingNotFoundException e) {
2893 // OS upgrade case where mode isn't set yet
2894 enabled = !TextUtils.isEmpty(Settings.Secure.getStringForUser(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002895 mContext.getContentResolver(),
2896 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002897 userId));
2898
2899 try {
2900 Settings.Secure.putIntForUser(
2901 mContext.getContentResolver(),
2902 Settings.Secure.LOCATION_MODE,
2903 enabled
2904 ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
2905 : Settings.Secure.LOCATION_MODE_OFF,
2906 userId);
2907 } catch (RuntimeException ex) {
2908 // any problem with writing should not be propagated
2909 Slog.e(TAG, "error updating location mode", ex);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002910 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002911 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002912 return enabled;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002913 } finally {
2914 Binder.restoreCallingIdentity(identity);
2915 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002916 }
2917
Maggie2a9409e2018-03-21 11:47:28 -07002918 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002919 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002920 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002921 if (UserHandle.getCallingUserId() != userId) {
2922 mContext.enforceCallingOrSelfPermission(
2923 Manifest.permission.INTERACT_ACROSS_USERS,
2924 "Requires INTERACT_ACROSS_USERS permission");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002925 }
2926
Maggie2a9409e2018-03-21 11:47:28 -07002927 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2928 // so we discourage its use
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002929 if (FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002930
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002931 synchronized (mLock) {
2932 LocationProvider provider = getLocationProviderLocked(providerName);
2933 return provider != null && provider.isUseableForUserLocked(userId);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002934 }
Maggie2a9409e2018-03-21 11:47:28 -07002935 }
2936
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002937 @GuardedBy("mLock")
2938 private boolean isLocationProviderLocked(int uid) {
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002939 if (uid == Process.SYSTEM_UID) {
2940 return true;
2941 }
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002942
David Christie1f141c12014-05-14 15:11:15 -07002943 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2944 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002945 return false;
2946 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002947 for (LocationProvider provider : mProviders) {
2948 String packageName = provider.getPackageLocked();
2949 if (packageName == null) {
2950 continue;
2951 }
2952 if (ArrayUtils.contains(packageNames, packageName)) {
David Christie1f141c12014-05-14 15:11:15 -07002953 return true;
2954 }
2955 }
2956 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002957 }
2958
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002959 @GuardedBy("mLock")
2960 private static boolean shouldBroadcastSafeLocked(
Laurent Tu75defb62012-11-01 16:21:52 -07002961 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002962 // Always broadcast the first update
2963 if (lastLoc == null) {
2964 return true;
2965 }
2966
Nick Pellyf1be6862012-05-15 10:53:42 -07002967 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002968 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002969 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2970 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002971 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002972 return false;
2973 }
2974
2975 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002976 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002977 if (minDistance > 0.0) {
2978 if (loc.distanceTo(lastLoc) <= minDistance) {
2979 return false;
2980 }
2981 }
2982
Laurent Tu75defb62012-11-01 16:21:52 -07002983 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002984 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002985 return false;
2986 }
2987
2988 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002989 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002990 }
2991
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002992 @GuardedBy("mLock")
2993 private void handleLocationChangedLocked(Location location, LocationProvider provider) {
2994 if (!mProviders.contains(provider)) {
2995 return;
2996 }
2997 if (!location.isComplete()) {
2998 Log.w(TAG, "Dropping incomplete location: " + location);
2999 return;
3000 }
3001
3002 if (!provider.isPassiveLocked()) {
3003 // notify passive provider of the new location
3004 mPassiveProvider.updateLocation(location);
3005 }
3006
Soonil Nagarkar68257742019-01-09 19:42:34 +00003007 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003008 long now = SystemClock.elapsedRealtime();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003009 updateLastLocationLocked(location, provider.getName());
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003010 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003011 Location lastLocation = mLastLocation.get(provider.getName());
Mike Lockwood4e50b782009-04-03 08:24:43 -07003012 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003013 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
3014 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07003015 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003016
David Christie1b9b7b12013-04-15 15:31:11 -07003017 // Update last known coarse interval location if enough time has passed.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003018 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider.getName());
David Christie1b9b7b12013-04-15 15:31:11 -07003019 if (lastLocationCoarseInterval == null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003020 lastLocationCoarseInterval = new Location(location);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003021 mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
David Christie1b9b7b12013-04-15 15:31:11 -07003022 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003023 long timeDiffNanos = location.getElapsedRealtimeNanos()
David Christie1b9b7b12013-04-15 15:31:11 -07003024 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
3025 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003026 lastLocationCoarseInterval.set(location);
David Christie1b9b7b12013-04-15 15:31:11 -07003027 }
3028 // Don't ever return a coarse location that is more recent than the allowed update
3029 // interval (i.e. don't allow an app to keep registering and unregistering for
3030 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003031 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07003032 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3033
Laurent Tu60ec50a2012-10-04 17:00:10 -07003034 // Skip if there are no UpdateRecords for this provider.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003035 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Laurent Tu60ec50a2012-10-04 17:00:10 -07003036 if (records == null || records.size() == 0) return;
3037
Victoria Lease09016ab2012-09-16 12:33:15 -07003038 // Fetch coarse location
3039 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07003040 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003041 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
3042 }
3043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003044 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003045 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07003046
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003047 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003048 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003049 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003050 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003051
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003052 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003053 if (!isCurrentProfileLocked(receiverUserId)
3054 && !isLocationProviderLocked(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003055 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003056 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003057 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003058 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003059 }
3060 continue;
3061 }
3062
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003063 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003064 if (D) {
3065 Log.d(TAG, "skipping loc update for blacklisted app: " +
3066 receiver.mIdentity.mPackageName);
3067 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003068 continue;
3069 }
3070
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003071 if (!reportLocationAccessNoThrow(
3072 receiver.mIdentity.mPid,
3073 receiver.mIdentity.mUid,
3074 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003075 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003076 if (D) {
3077 Log.d(TAG, "skipping loc update for no op app: " +
3078 receiver.mIdentity.mPackageName);
3079 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003080 continue;
3081 }
3082
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003083 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003084 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3085 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003086 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07003087 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003088 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003089 if (notifyLocation != null) {
3090 Location lastLoc = r.mLastFixBroadcast;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003091 if ((lastLoc == null)
3092 || shouldBroadcastSafeLocked(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003093 if (lastLoc == null) {
3094 lastLoc = new Location(notifyLocation);
3095 r.mLastFixBroadcast = lastLoc;
3096 } else {
3097 lastLoc.set(notifyLocation);
3098 }
3099 if (!receiver.callLocationChangedLocked(notifyLocation)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003100 Slog.w(TAG, "RemoteException calling onLocationChanged on "
3101 + receiver);
Victoria Lease09016ab2012-09-16 12:33:15 -07003102 receiverDead = true;
3103 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003104 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105 }
3106 }
3107
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003108 // TODO: location provider status callbacks have been disabled and deprecated, and are
3109 // guarded behind this setting now. should be removed completely post-Q
3110 if (Settings.Global.getInt(mContext.getContentResolver(),
3111 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003112 long newStatusUpdateTime = provider.getStatusUpdateTimeLocked();
3113 Bundle extras = new Bundle();
3114 int status = provider.getStatusLocked(extras);
3115
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003116 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3117 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003118 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003119
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003120 r.mLastStatusBroadcast = newStatusUpdateTime;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003121 if (!receiver.callStatusChangedLocked(provider.getName(), status, extras)) {
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003122 receiverDead = true;
3123 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3124 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003125 }
3126 }
3127
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003128 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003129 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003130 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003131 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003132 }
3133 deadUpdateRecords.add(r);
3134 }
3135 // track dead receivers
3136 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003137 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003138 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003139 }
3140 if (!deadReceivers.contains(receiver)) {
3141 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003142 }
3143 }
3144 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003145
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003146 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003147 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003148 for (Receiver receiver : deadReceivers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003149 removeUpdatesLocked(receiver);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003150 }
3151 }
3152 if (deadUpdateRecords != null) {
3153 for (UpdateRecord r : deadUpdateRecords) {
3154 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003155 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003156 applyRequirementsLocked(provider);
Victoria Lease8b38b292012-12-04 15:04:43 -08003157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158 }
3159
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003160 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00003161 private void updateLastLocationLocked(Location location, String provider) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003162 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3163 Location lastNoGPSLocation;
3164 Location lastLocation = mLastLocation.get(provider);
3165 if (lastLocation == null) {
3166 lastLocation = new Location(provider);
3167 mLastLocation.put(provider, lastLocation);
3168 } else {
3169 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3170 if (noGPSLocation == null && lastNoGPSLocation != null) {
3171 // New location has no no-GPS location: adopt last no-GPS location. This is set
3172 // directly into location because we do not want to notify COARSE clients.
3173 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3174 }
3175 }
3176 lastLocation.set(location);
3177 }
3178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 // Geocoder
3180
Nick Pellye0fd6932012-07-11 10:26:13 -07003181 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003182 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003183 return mGeocodeProvider != null;
3184 }
3185
Nick Pellye0fd6932012-07-11 10:26:13 -07003186 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003188 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003189 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003190 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3191 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003192 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003193 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194 }
3195
Mike Lockwooda55c3212009-04-15 11:10:11 -04003196
Nick Pellye0fd6932012-07-11 10:26:13 -07003197 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003198 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003199 double lowerLeftLatitude, double lowerLeftLongitude,
3200 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003201 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003202
3203 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003204 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3205 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3206 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003207 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003208 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003209 }
3210
3211 // Mock Providers
3212
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003213 private boolean canCallerAccessMockLocation(String opPackageName) {
3214 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3215 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 }
3217
Nick Pellye0fd6932012-07-11 10:26:13 -07003218 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003219 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003220 if (!canCallerAccessMockLocation(opPackageName)) {
3221 return;
3222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003224 if (PASSIVE_PROVIDER.equals(name)) {
Mike Lockwooda4903f22010-02-17 06:42:23 -05003225 throw new IllegalArgumentException("Cannot mock the passive location provider");
3226 }
3227
Soonil Nagarkar68257742019-01-09 19:42:34 +00003228 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003229 long identity = Binder.clearCallingIdentity();
3230 try {
3231 LocationProvider oldProvider = getLocationProviderLocked(name);
3232 if (oldProvider != null) {
3233 if (oldProvider.isMock()) {
3234 throw new IllegalArgumentException(
3235 "Provider \"" + name + "\" already exists");
3236 }
3237
3238 removeProviderLocked(oldProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003239 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003240
3241 MockLocationProvider mockProviderManager = new MockLocationProvider(name);
3242 addProviderLocked(mockProviderManager);
3243 mockProviderManager.attachLocked(new MockProvider(mockProviderManager, properties));
3244 } finally {
3245 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003246 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003247 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003248 }
3249
Nick Pellye0fd6932012-07-11 10:26:13 -07003250 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003251 public void removeTestProvider(String name, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003252 if (!canCallerAccessMockLocation(opPackageName)) {
3253 return;
3254 }
3255
Soonil Nagarkar68257742019-01-09 19:42:34 +00003256 synchronized (mLock) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003257 long identity = Binder.clearCallingIdentity();
3258 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003259 LocationProvider testProvider = getLocationProviderLocked(name);
3260 if (testProvider == null || !testProvider.isMock()) {
3261 throw new IllegalArgumentException("Provider \"" + name + "\" unknown");
3262 }
3263
3264 removeProviderLocked(testProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003265
Soonil Nagarkar68257742019-01-09 19:42:34 +00003266 // reinstate real provider if available
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003267 LocationProvider realProvider = null;
3268 for (LocationProvider provider : mRealProviders) {
3269 if (name.equals(provider.getName())) {
3270 realProvider = provider;
3271 break;
3272 }
3273 }
3274
Soonil Nagarkar68257742019-01-09 19:42:34 +00003275 if (realProvider != null) {
3276 addProviderLocked(realProvider);
3277 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003278 } finally {
3279 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003280 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003281 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003282 }
3283
Nick Pellye0fd6932012-07-11 10:26:13 -07003284 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003285 public void setTestProviderLocation(String providerName, Location location,
Soonil Nagarkar68257742019-01-09 19:42:34 +00003286 String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003287 if (!canCallerAccessMockLocation(opPackageName)) {
3288 return;
3289 }
3290
Soonil Nagarkar68257742019-01-09 19:42:34 +00003291 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003292 LocationProvider testProvider = getLocationProviderLocked(providerName);
3293 if (testProvider == null || !testProvider.isMock()) {
3294 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003296
3297 String locationProvider = location.getProvider();
3298 if (!TextUtils.isEmpty(locationProvider) && !providerName.equals(locationProvider)) {
3299 // The location has an explicit provider that is different from the mock
3300 // provider name. The caller may be trying to fool us via b/33091107.
3301 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3302 providerName + "!=" + location.getProvider());
3303 }
3304
3305 ((MockLocationProvider) testProvider).setLocationLocked(location);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003306 }
3307 }
3308
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003309 @Override
3310 public void setTestProviderEnabled(String providerName, boolean enabled, String opPackageName) {
3311 if (!canCallerAccessMockLocation(opPackageName)) {
3312 return;
3313 }
3314
3315 synchronized (mLock) {
3316 LocationProvider testProvider = getLocationProviderLocked(providerName);
3317 if (testProvider == null || !testProvider.isMock()) {
3318 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3319 }
3320
3321 ((MockLocationProvider) testProvider).setEnabledLocked(enabled);
3322 }
3323 }
3324
3325 @Override
3326 public void setTestProviderStatus(String providerName, int status, Bundle extras,
3327 long updateTime, String opPackageName) {
3328 if (!canCallerAccessMockLocation(opPackageName)) {
3329 return;
3330 }
3331
3332 synchronized (mLock) {
3333 LocationProvider testProvider = getLocationProviderLocked(providerName);
3334 if (testProvider == null || !testProvider.isMock()) {
3335 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3336 }
3337
3338 ((MockLocationProvider) testProvider).setStatusLocked(status, extras, updateTime);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003339 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003340 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003341
3342 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003344 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003345
Soonil Nagarkar68257742019-01-09 19:42:34 +00003346 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003347 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3348 if (mGnssMetricsProvider != null) {
3349 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3350 }
3351 return;
3352 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003353 pw.println("Current Location Manager state:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003354 pw.println(" Location Mode: " + isLocationEnabled());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003355 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003356 for (Receiver receiver : mReceivers.values()) {
3357 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003358 }
David Christie2ff96af2014-01-30 16:09:37 -08003359 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003360 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3361 pw.println(" " + entry.getKey() + ":");
3362 for (UpdateRecord record : entry.getValue()) {
3363 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 }
3365 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003366 pw.println(" Active GnssMeasurement Listeners:");
3367 for (Identity identity : mGnssMeasurementsListeners.values()) {
3368 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3369 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3370 }
3371 pw.println(" Active GnssNavigationMessage Listeners:");
3372 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3373 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3374 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3375 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003376 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003377 for (LocationProvider provider : mProviders) {
3378 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003379 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003380 + ((LocationProviderProxy) provider.mProvider)
3381 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003382 }
3383 }
David Christie2ff96af2014-01-30 16:09:37 -08003384 pw.println(" Historical Records by Provider:");
3385 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3386 : mRequestStatistics.statistics.entrySet()) {
3387 PackageProviderKey key = entry.getKey();
3388 PackageStatistics stats = entry.getValue();
3389 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3390 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003391 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003392 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3393 String provider = entry.getKey();
3394 Location location = entry.getValue();
3395 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003397
David Christie1b9b7b12013-04-15 15:31:11 -07003398 pw.println(" Last Known Locations Coarse Intervals:");
3399 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3400 String provider = entry.getKey();
3401 Location location = entry.getValue();
3402 pw.println(" " + provider + ": " + location);
3403 }
3404
Nick Pellye0fd6932012-07-11 10:26:13 -07003405 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003406
Nick Pelly4035f5a2012-08-17 14:43:49 -07003407 pw.append(" ");
3408 mBlacklist.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003409
Wei Wang980b7c22018-12-06 17:53:00 -08003410 if (mLocationControllerExtraPackage != null) {
3411 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
3412 + " enabled: " + mLocationControllerExtraPackageEnabled);
3413 }
3414
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003415 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3416 pw.println(" Throttling Whitelisted Packages:");
3417 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3418 pw.println(" " + packageName);
3419 }
3420 }
3421
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003422 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003423 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003424
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003425 if (args.length > 0 && "short".equals(args[0])) {
3426 return;
3427 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003428 for (LocationProvider provider : mProviders) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003429 provider.dumpLocked(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003430 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003431 if (mGnssBatchingInProgress) {
3432 pw.println(" GNSS batching in progress");
3433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003434 }
3435 }
3436}