blob: 4c72b3596305fd7f4eb282545afd4607ff32a27d [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));
Wei Wangffb94e62019-01-14 00:05:45 -0800260 packageManagerInternal.setLocationExtraPackagesProvider(
261 userId -> mContext.getResources().getStringArray(
262 com.android.internal.R.array.config_locationExtraPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700263
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700264 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700265 }
266
Svetoslav Ganova0027152013-06-25 14:59:53 -0700267 public void systemRunning() {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000268 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800269 initializeLocked();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800270 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800271 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700272
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800273 @GuardedBy("mLock")
274 private void initializeLocked() {
275 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
276 mPackageManager = mContext.getPackageManager();
277 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
278 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
279 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
280
281 mLocationFudger = new LocationFudger(mContext, mHandler);
282 mBlacklist = new LocationBlacklist(mContext, mHandler);
283 mBlacklist.init();
284 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
285
286 // prepare providers
287 initializeProvidersLocked();
288
289 // add listeners
290 mAppOps.startWatchingMode(
291 AppOpsManager.OP_COARSE_LOCATION,
292 null,
293 AppOpsManager.WATCH_FOREGROUND_CHANGES,
294 new AppOpsManager.OnOpChangedInternalListener() {
295 public void onOpChanged(int op, String packageName) {
296 synchronized (mLock) {
297 onAppOpChangedLocked();
298 }
299 }
300 });
301 mPackageManager.addOnPermissionsChangeListener(
302 uid -> {
303 synchronized (mLock) {
304 onPermissionsChangedLocked();
305 }
306 });
307
308 mActivityManager.addOnUidImportanceListener(
309 (uid, importance) -> {
310 synchronized (mLock) {
311 onUidImportanceChangedLocked(uid, importance);
312 }
313 },
314 FOREGROUND_IMPORTANCE_CUTOFF);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700315 mContext.getContentResolver().registerContentObserver(
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800316 Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), true,
317 new ContentObserver(mHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800318 @Override
319 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000320 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800321 onLocationModeChangedLocked(true);
322 }
323 }
324 }, UserHandle.USER_ALL);
325 mContext.getContentResolver().registerContentObserver(
326 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
327 new ContentObserver(mHandler) {
328 @Override
329 public void onChange(boolean selfChange) {
330 synchronized (mLock) {
331 onProviderAllowedChangedLocked(true);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000332 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800333 }
334 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800335 mContext.getContentResolver().registerContentObserver(
336 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
337 true,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800338 new ContentObserver(mHandler) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800339 @Override
340 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000341 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800342 onBackgroundThrottleIntervalChangedLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000343 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800344 }
345 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800346 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800347 Settings.Global.getUriFor(
348 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
349 true,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800350 new ContentObserver(mHandler) {
gomo48f1a642017-11-10 20:35:46 -0800351 @Override
352 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000353 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800354 onBackgroundThrottleWhitelistChangedLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000355 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800356 }
gomo48f1a642017-11-10 20:35:46 -0800357 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700358
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800359 new PackageMonitor() {
360 @Override
361 public void onPackageDisappeared(String packageName, int reason) {
362 synchronized (mLock) {
363 LocationManagerService.this.onPackageDisappearedLocked(packageName);
364 }
365 }
366 }.register(mContext, mHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700367
Victoria Lease38389b62012-09-30 11:44:22 -0700368 IntentFilter intentFilter = new IntentFilter();
369 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700370 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
371 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700372
373 mContext.registerReceiverAsUser(new BroadcastReceiver() {
374 @Override
375 public void onReceive(Context context, Intent intent) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800376 synchronized (mLock) {
377 String action = intent.getAction();
378 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
379 onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
380 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
381 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
382 onUserProfilesChangedLocked();
383 }
Victoria Lease38389b62012-09-30 11:44:22 -0700384 }
385 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800386 }, UserHandle.ALL, intentFilter, null, mHandler);
387
388 // switching the user from null to system here performs the bulk of the initialization work.
389 // the user being changed will cause a reload of all user specific settings, which causes
390 // provider initialization, and propagates changes until a steady state is reached
391 mCurrentUserId = UserHandle.USER_NULL;
392 onUserChangedLocked(UserHandle.USER_SYSTEM);
393
394 // initialize in-memory settings values
395 onBackgroundThrottleWhitelistChangedLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700396 }
397
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800398 @GuardedBy("mLock")
399 private void onAppOpChangedLocked() {
400 for (Receiver receiver : mReceivers.values()) {
401 receiver.updateMonitoring(true);
402 }
403 for (LocationProvider p : mProviders) {
404 applyRequirementsLocked(p);
405 }
406 }
407
408 @GuardedBy("mLock")
409 private void onPermissionsChangedLocked() {
410 for (LocationProvider p : mProviders) {
411 applyRequirementsLocked(p);
412 }
413 }
414
415 @GuardedBy("mLock")
416 private void onLocationModeChangedLocked(boolean broadcast) {
417 for (LocationProvider p : mProviders) {
418 p.onLocationModeChangedLocked();
419 }
420
421 if (broadcast) {
422 mContext.sendBroadcastAsUser(
423 new Intent(LocationManager.MODE_CHANGED_ACTION),
424 UserHandle.ALL);
425 }
426 }
427
428 @GuardedBy("mLock")
429 private void onProviderAllowedChangedLocked(boolean broadcast) {
430 for (LocationProvider p : mProviders) {
431 p.onAllowedChangedLocked();
432 }
433
434 if (broadcast) {
435 mContext.sendBroadcastAsUser(
436 new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
437 UserHandle.ALL);
438 }
439 }
440
441 @GuardedBy("mLock")
442 private void onPackageDisappearedLocked(String packageName) {
443 ArrayList<Receiver> deadReceivers = null;
444
445 for (Receiver receiver : mReceivers.values()) {
446 if (receiver.mIdentity.mPackageName.equals(packageName)) {
447 if (deadReceivers == null) {
448 deadReceivers = new ArrayList<>();
449 }
450 deadReceivers.add(receiver);
451 }
452 }
453
454 // perform removal outside of mReceivers loop
455 if (deadReceivers != null) {
456 for (Receiver receiver : deadReceivers) {
457 removeUpdatesLocked(receiver);
458 }
459 }
460 }
461
462 @GuardedBy("mLock")
463 private void onUidImportanceChangedLocked(int uid, int importance) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700464 boolean foreground = isImportanceForeground(importance);
465 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800466 for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
467 String provider = entry.getKey();
468 for (UpdateRecord record : entry.getValue()) {
469 if (record.mReceiver.mIdentity.mUid == uid
470 && record.mIsForegroundUid != foreground) {
gomo48f1a642017-11-10 20:35:46 -0800471 if (D) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800472 Log.d(TAG, "request from uid " + uid + " is now "
gomo48f1a642017-11-10 20:35:46 -0800473 + (foreground ? "foreground" : "background)"));
474 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800475 record.updateForeground(foreground);
476
477 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
478 affectedProviders.add(provider);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700479 }
480 }
481 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800482 }
483 for (String provider : affectedProviders) {
484 applyRequirementsLocked(provider);
485 }
Anil Admal75b9fd62018-11-28 11:22:50 -0800486
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800487 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
488 Identity callerIdentity = entry.getValue();
489 if (callerIdentity.mUid == uid) {
490 if (D) {
491 Log.d(TAG, "gnss measurements listener from uid " + uid
492 + " is now " + (foreground ? "foreground" : "background)"));
493 }
494 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
495 mGnssMeasurementsProvider.addListener(
496 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
497 callerIdentity.mUid, callerIdentity.mPackageName);
498 } else {
499 mGnssMeasurementsProvider.removeListener(
500 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
501 }
502 }
503 }
504
505 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
506 Identity callerIdentity = entry.getValue();
507 if (callerIdentity.mUid == uid) {
508 if (D) {
509 Log.d(TAG, "gnss navigation message listener from uid "
510 + uid + " is now "
511 + (foreground ? "foreground" : "background)"));
512 }
513 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
514 mGnssNavigationMessageProvider.addListener(
515 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
516 callerIdentity.mUid, callerIdentity.mPackageName);
517 } else {
518 mGnssNavigationMessageProvider.removeListener(
519 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
520 }
521 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700522 }
523 }
524
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800525 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700526 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800527 }
528
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800529 @GuardedBy("mLock")
530 private void onBackgroundThrottleIntervalChangedLocked() {
531 for (LocationProvider provider : mProviders) {
532 applyRequirementsLocked(provider);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000533 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800534 }
535
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800536 @GuardedBy("mLock")
537 private void onBackgroundThrottleWhitelistChangedLocked() {
538 String setting = Settings.Global.getString(
539 mContext.getContentResolver(),
540 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
541 if (setting == null) {
542 setting = "";
543 }
544
545 mBackgroundThrottlePackageWhitelist.clear();
546 mBackgroundThrottlePackageWhitelist.addAll(
547 SystemConfig.getInstance().getAllowUnthrottledLocation());
548 mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(",")));
549
550 for (LocationProvider p : mProviders) {
551 applyRequirementsLocked(p);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000552 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800553 }
554
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800555 @GuardedBy("mLock")
556 private void onUserProfilesChangedLocked() {
557 mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(mCurrentUserId);
558 }
559
560 @GuardedBy("mLock")
561 private boolean isCurrentProfileLocked(int userId) {
562 return ArrayUtils.contains(mCurrentUserProfiles, userId);
563 }
564
565 @GuardedBy("mLock")
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700566 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500567 PackageManager pm = mContext.getPackageManager();
568 String systemPackageName = mContext.getPackageName();
569 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
570
571 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
572 new Intent(FUSED_LOCATION_SERVICE_ACTION),
573 PackageManager.GET_META_DATA, mCurrentUserId);
574 for (ResolveInfo rInfo : rInfos) {
575 String packageName = rInfo.serviceInfo.packageName;
576
577 // Check that the signature is in the list of supported sigs. If it's not in
578 // this list the standard provider binding logic won't bind to it.
579 try {
580 PackageInfo pInfo;
581 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
582 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
583 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
584 ", but has wrong signature, ignoring");
585 continue;
586 }
587 } catch (NameNotFoundException e) {
588 Log.e(TAG, "missing package: " + packageName);
589 continue;
590 }
591
592 // Get the version info
593 if (rInfo.serviceInfo.metaData == null) {
594 Log.w(TAG, "Found fused provider without metadata: " + packageName);
595 continue;
596 }
597
598 int version = rInfo.serviceInfo.metaData.getInt(
599 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
600 if (version == 0) {
601 // This should be the fallback fused location provider.
602
603 // Make sure it's in the system partition.
604 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
605 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
606 continue;
607 }
608
609 // Check that the fallback is signed the same as the OS
610 // as a proxy for coreApp="true"
611 if (pm.checkSignatures(systemPackageName, packageName)
612 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800613 if (D) {
614 Log.d(TAG, "Fallback candidate not signed the same as system: "
615 + packageName);
616 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500617 continue;
618 }
619
620 // Found a valid fallback.
621 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
622 return;
623 } else {
624 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
625 }
626 }
627
628 throw new IllegalStateException("Unable to find a fused location provider that is in the "
629 + "system partition with version 0 and signed with the platform certificate. "
630 + "Such a package is needed to provide a default fused location provider in the "
631 + "event that no other fused location provider has been installed or is currently "
632 + "available. For example, coreOnly boot mode when decrypting the data "
633 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
634 }
635
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800636 @GuardedBy("mLock")
637 private void initializeProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700638 // create a passive location provider, which is always enabled
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800639 LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000640 addProviderLocked(passiveProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800641 mPassiveProvider = new PassiveProvider(passiveProviderManager);
642 passiveProviderManager.attachLocked(mPassiveProvider);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700643
Lifu Tang30f95a72016-01-07 23:20:38 -0800644 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700645 // Create a gps location provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800646 LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
647 mRealProviders.add(gnssProviderManager);
648 addProviderLocked(gnssProviderManager);
649
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700650 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
651 gnssProviderManager,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800652 mHandler.getLooper());
653 gnssProviderManager.attachLocked(gnssProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700654
Lifu Tang9363b942016-02-16 18:07:00 -0800655 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800656 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700657 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800658 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
659 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
Lifu Tang818aa2c2016-02-01 01:52:00 -0800660 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
661 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800662 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700663 }
664
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700665 /*
666 Load package name(s) containing location provider support.
667 These packages can contain services implementing location providers:
668 Geocoder Provider, Network Location Provider, and
669 Fused Location Provider. They will each be searched for
670 service components implementing these providers.
671 The location framework also has support for installation
672 of new location providers at run-time. The new package does not
673 have to be explicitly listed here, however it must have a signature
674 that matches the signature of at least one package on this list.
675 */
676 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500677 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700678 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800679 if (D) {
680 Log.d(TAG, "certificates for location providers pulled from: " +
681 Arrays.toString(pkgs));
682 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500683
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700684 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700685
686 // bind to network provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800687 LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER, true);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700688 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
689 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700690 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700691 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700692 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
693 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700694 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700695 if (networkProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800696 mRealProviders.add(networkProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000697 addProviderLocked(networkProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800698 networkProviderManager.attachLocked(networkProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700699 } else {
gomo48f1a642017-11-10 20:35:46 -0800700 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700701 }
702
703 // bind to fused provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800704 LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700705 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700706 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700707 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700708 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700709 com.android.internal.R.bool.config_enableFusedLocationOverlay,
710 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700711 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700712 if (fusedProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800713 mRealProviders.add(fusedProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000714 addProviderLocked(fusedProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800715 fusedProviderManager.attachLocked(fusedProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700716 } else {
717 Slog.e(TAG, "no fused location provider found",
718 new IllegalStateException("Location service needs a fused location provider"));
719 }
720
721 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700722 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
723 com.android.internal.R.bool.config_enableGeocoderOverlay,
724 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700725 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700726 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800727 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700728 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700729
destradaaf9a274c2014-07-25 15:11:56 -0700730 // bind to geofence provider
731 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800732 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700733 com.android.internal.R.string.config_geofenceProviderPackageName,
734 com.android.internal.R.array.config_locationProviderPackageNames,
Wei Liu5241a4c2015-05-11 14:00:36 -0700735 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900736 null);
destradaaf9a274c2014-07-25 15:11:56 -0700737 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800738 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700739 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900740
destradaa6e2fe752015-06-23 17:25:53 -0700741 // bind to hardware activity recognition
742 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
743 ActivityRecognitionHardware activityRecognitionHardware = null;
744 if (activityRecognitionHardwareIsSupported) {
745 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
destradaaa4fa3b52014-07-09 10:46:39 -0700746 } else {
destradaa6b4893a2016-05-03 15:33:43 -0700747 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
destradaaa4fa3b52014-07-09 10:46:39 -0700748 }
destradaa6e2fe752015-06-23 17:25:53 -0700749 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
750 mContext,
destradaa6e2fe752015-06-23 17:25:53 -0700751 activityRecognitionHardwareIsSupported,
752 activityRecognitionHardware,
753 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
754 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
755 com.android.internal.R.array.config_locationProviderPackageNames);
756 if (proxy == null) {
destradaa6b4893a2016-05-03 15:33:43 -0700757 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
destradaa6e2fe752015-06-23 17:25:53 -0700758 }
destradaaa4fa3b52014-07-09 10:46:39 -0700759
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900760 String[] testProviderStrings = resources.getStringArray(
761 com.android.internal.R.array.config_testLocationProviders);
762 for (String testProviderString : testProviderStrings) {
763 String fragments[] = testProviderString.split(",");
764 String name = fragments[0].trim();
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900765 ProviderProperties properties = new ProviderProperties(
766 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
767 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
768 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
769 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
770 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
771 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
772 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
773 Integer.parseInt(fragments[8]) /* powerRequirement */,
774 Integer.parseInt(fragments[9]) /* accuracy */);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800775 LocationProvider testProviderManager = new LocationProvider(name);
776 addProviderLocked(testProviderManager);
777 new MockProvider(testProviderManager, properties);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900778 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700779 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700780
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800781 @GuardedBy("mLock")
782 private void onUserChangedLocked(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800783 if (mCurrentUserId == userId) {
784 return;
785 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800786
787 // this call has the side effect of forcing a write to the LOCATION_MODE setting in an OS
788 // upgrade case, and ensures that if anyone checks the LOCATION_MODE setting directly, they
789 // will see it in an appropriate state (at least after that user becomes foreground for the
790 // first time...)
791 isLocationEnabledForUser(userId);
792
793 // let providers know the current user is on the way out before changing the user
794 for (LocationProvider p : mProviders) {
795 p.onUserChangingLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000796 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800797
798 mCurrentUserId = userId;
799 onUserProfilesChangedLocked();
800
801 mBlacklist.switchUser(userId);
802
803 // if the user changes, per-user settings may also have changed
804 onLocationModeChangedLocked(false);
805 onProviderAllowedChangedLocked(false);
Victoria Lease38389b62012-09-30 11:44:22 -0700806 }
807
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800808 private static final class Identity {
809 final int mUid;
810 final int mPid;
811 final String mPackageName;
812
813 Identity(int uid, int pid, String packageName) {
814 mUid = uid;
815 mPid = pid;
816 mPackageName = packageName;
817 }
818 }
819
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700820 private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
821
822 private final String mName;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700823
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800824 // whether this provider should respect LOCATION_PROVIDERS_ALLOWED (ie gps and network)
825 private final boolean mIsManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700826
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800827 // remember to clear binder identity before invoking any provider operation
828 @GuardedBy("mLock")
829 @Nullable protected AbstractLocationProvider mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700830
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800831 @GuardedBy("mLock")
832 private boolean mUseable; // combined state
833 @GuardedBy("mLock")
834 private boolean mAllowed; // state of LOCATION_PROVIDERS_ALLOWED
835 @GuardedBy("mLock")
836 private boolean mEnabled; // state of provider
837
838 @GuardedBy("mLock")
839 @Nullable private ProviderProperties mProperties;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700840
841 private LocationProvider(String name) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800842 this(name, false);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700843 }
844
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800845 private LocationProvider(String name, boolean isManagedBySettings) {
846 mName = name;
847 mIsManagedBySettings = isManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700848
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800849 mProvider = null;
850 mUseable = false;
851 mAllowed = !mIsManagedBySettings;
852 mEnabled = false;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700853 mProperties = null;
854 }
855
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800856 @GuardedBy("mLock")
857 public void attachLocked(AbstractLocationProvider provider) {
858 checkNotNull(provider);
859 checkState(mProvider == null);
860 mProvider = provider;
861
862 onUseableChangedLocked();
863 }
864
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700865 public String getName() {
866 return mName;
867 }
868
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800869 @GuardedBy("mLock")
870 @Nullable
871 public String getPackageLocked() {
872 if (mProvider == null) {
873 return null;
874 } else if (mProvider instanceof LocationProviderProxy) {
875 // safe to not clear binder context since this doesn't call into the actual provider
876 return ((LocationProviderProxy) mProvider).getConnectedPackageName();
877 } else {
878 return mContext.getPackageName();
879 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700880 }
881
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800882 public boolean isMock() {
883 return false;
884 }
885
886 @GuardedBy("mLock")
887 public boolean isPassiveLocked() {
888 return mProvider == mPassiveProvider;
889 }
890
891 @GuardedBy("mLock")
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700892 @Nullable
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800893 public ProviderProperties getPropertiesLocked() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700894 return mProperties;
895 }
896
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800897 @GuardedBy("mLock")
898 public void setRequestLocked(ProviderRequest request, WorkSource workSource) {
899 if (mProvider != null) {
900 long identity = Binder.clearCallingIdentity();
901 try {
902 mProvider.setRequest(request, workSource);
903 } finally {
904 Binder.restoreCallingIdentity(identity);
905 }
906 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700907 }
908
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800909 @GuardedBy("mLock")
910 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700911 pw.println(mName + " provider:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800912 if (isMock()) {
913 pw.println(" mock=true");
914 }
915 pw.println(" attached=" + (mProvider != null));
916 if (mIsManagedBySettings) {
917 pw.println(" allowed=" + mAllowed);
918 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700919 pw.println(" enabled=" + mEnabled);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800920 pw.println(" useable=" + mUseable);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700921 pw.println(" properties=" + mProperties);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800922
923 if (mProvider != null) {
924 long identity = Binder.clearCallingIdentity();
925 try {
926 mProvider.dump(fd, pw, args);
927 } finally {
928 Binder.restoreCallingIdentity(identity);
929 }
930 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700931 }
932
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800933 @GuardedBy("mLock")
934 public long getStatusUpdateTimeLocked() {
935 if (mProvider != null) {
936 long identity = Binder.clearCallingIdentity();
937 try {
938 return mProvider.getStatusUpdateTime();
939 } finally {
940 Binder.restoreCallingIdentity(identity);
941 }
942 } else {
943 return 0;
944 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700945 }
946
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800947 @GuardedBy("mLock")
948 public int getStatusLocked(Bundle extras) {
949 if (mProvider != null) {
950 long identity = Binder.clearCallingIdentity();
951 try {
952 return mProvider.getStatus(extras);
953 } finally {
954 Binder.restoreCallingIdentity(identity);
955 }
956 } else {
957 return AVAILABLE;
958 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700959 }
960
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800961 @GuardedBy("mLock")
962 public void sendExtraCommandLocked(String command, Bundle extras) {
963 if (mProvider != null) {
964 long identity = Binder.clearCallingIdentity();
965 try {
966 mProvider.sendExtraCommand(command, extras);
967 } finally {
968 Binder.restoreCallingIdentity(identity);
969 }
970 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700971 }
972
973 // called from any thread
974 @Override
975 public void onReportLocation(Location location) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800976 // no security check necessary because this is coming from an internal-only interface
977 // move calls coming from below LMS onto a different thread to avoid deadlock
978 runInternal(() -> {
979 synchronized (mLock) {
980 handleLocationChangedLocked(location, this);
981 }
982 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700983 }
984
985 // called from any thread
986 @Override
987 public void onReportLocation(List<Location> locations) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800988 // move calls coming from below LMS onto a different thread to avoid deadlock
989 runInternal(() -> {
990 synchronized (mLock) {
991 LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
992 if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
993 Slog.w(TAG, "reportLocationBatch() called without user permission");
994 return;
995 }
996
997 if (mGnssBatchingCallback == null) {
998 Slog.e(TAG, "reportLocationBatch() called without active Callback");
999 return;
1000 }
1001
1002 try {
1003 mGnssBatchingCallback.onLocationBatch(locations);
1004 } catch (RemoteException e) {
1005 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1006 }
1007 }
1008 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001009 }
1010
1011 // called from any thread
1012 @Override
1013 public void onSetEnabled(boolean enabled) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001014 // move calls coming from below LMS onto a different thread to avoid deadlock
1015 runInternal(() -> {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001016 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001017 if (enabled == mEnabled) {
1018 return;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001019 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001020
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001021 mEnabled = enabled;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001022
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001023 // update provider allowed settings to reflect enabled status
1024 if (mIsManagedBySettings) {
1025 if (mEnabled && !mAllowed) {
1026 Settings.Secure.putStringForUser(
1027 mContext.getContentResolver(),
1028 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1029 "+" + mName,
1030 mCurrentUserId);
1031 } else if (!mEnabled && mAllowed) {
1032 Settings.Secure.putStringForUser(
1033 mContext.getContentResolver(),
1034 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1035 "-" + mName,
1036 mCurrentUserId);
1037 }
1038 }
1039
1040 onUseableChangedLocked();
1041 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001042 });
1043 }
1044
1045 @Override
1046 public void onSetProperties(ProviderProperties properties) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001047 // move calls coming from below LMS onto a different thread to avoid deadlock
1048 runInternal(() -> {
1049 synchronized (mLock) {
1050 mProperties = properties;
1051 }
1052 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001053 }
1054
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001055 @GuardedBy("mLock")
1056 public void onLocationModeChangedLocked() {
1057 onUseableChangedLocked();
1058 }
1059
1060 private boolean isAllowed() {
1061 return isAllowedForUser(mCurrentUserId);
1062 }
1063
1064 private boolean isAllowedForUser(int userId) {
1065 String allowedProviders = Settings.Secure.getStringForUser(
1066 mContext.getContentResolver(),
1067 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1068 userId);
1069 return TextUtils.delimitedStringContains(allowedProviders, ',', mName);
1070 }
1071
1072 @GuardedBy("mLock")
1073 public void onAllowedChangedLocked() {
1074 if (mIsManagedBySettings) {
1075 boolean allowed = isAllowed();
1076 if (allowed == mAllowed) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001077 return;
1078 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001079 mAllowed = allowed;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001080
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001081 // make a best effort to keep the setting matching the real enabled state of the
1082 // provider so that legacy applications aren't broken.
1083 if (mAllowed && !mEnabled) {
1084 Settings.Secure.putStringForUser(
1085 mContext.getContentResolver(),
1086 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1087 "-" + mName,
1088 mCurrentUserId);
1089 }
1090
1091 onUseableChangedLocked();
1092 }
1093 }
1094
1095 @GuardedBy("mLock")
1096 public boolean isUseableLocked() {
1097 return isUseableForUserLocked(mCurrentUserId);
1098 }
1099
1100 @GuardedBy("mLock")
1101 public boolean isUseableForUserLocked(int userId) {
1102 return userId == mCurrentUserId && mUseable;
1103 }
1104
1105 @GuardedBy("mLock")
1106 public void onUseableChangedLocked() {
1107 // if any property that contributes to "useability" here changes state, it MUST result
1108 // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
1109 // guarantee that it will always eventually reach the correct state.
1110 boolean useable = mProvider != null
1111 && mProviders.contains(this) && isLocationEnabled() && mAllowed && mEnabled;
1112 if (useable == mUseable) {
1113 return;
1114 }
1115 mUseable = useable;
1116
1117 if (!mUseable) {
1118 // If any provider has been disabled, clear all last locations for all
1119 // providers. This is to be on the safe side in case a provider has location
1120 // derived from this disabled provider.
1121 mLastLocation.clear();
1122 mLastLocationCoarseInterval.clear();
1123 }
1124
1125 updateProviderUseableLocked(this);
1126 }
1127
1128 @GuardedBy("mLock")
1129 public void onUserChangingLocked() {
1130 // when the user is about to change, we set this provider to un-useable, and notify all
1131 // of the current user clients. when the user is finished changing, useability will be
1132 // updated back via onLocationModeChanged() and onAllowedChanged().
1133 mUseable = false;
1134 updateProviderUseableLocked(this);
1135 }
1136
1137 // binder transactions coming from below LMS (ie location providers) need to be moved onto
1138 // a different thread to avoid potential deadlock as code reenters the location providers
1139 private void runInternal(Runnable runnable) {
1140 if (Looper.myLooper() == mHandler.getLooper()) {
1141 runnable.run();
1142 } else {
1143 mHandler.post(runnable);
1144 }
1145 }
1146 }
1147
1148 private class MockLocationProvider extends LocationProvider {
1149
1150 private MockLocationProvider(String name) {
1151 super(name);
1152 }
1153
1154 @Override
1155 public void attachLocked(AbstractLocationProvider provider) {
1156 checkState(provider instanceof MockProvider);
1157 super.attachLocked(provider);
1158 }
1159
1160 public boolean isMock() {
1161 return true;
1162 }
1163
1164 @GuardedBy("mLock")
1165 public void setEnabledLocked(boolean enabled) {
1166 if (mProvider != null) {
1167 long identity = Binder.clearCallingIdentity();
1168 try {
1169 ((MockProvider) mProvider).setEnabled(enabled);
1170 } finally {
1171 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00001172 }
1173 }
1174 }
1175
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001176 @GuardedBy("mLock")
1177 public void setLocationLocked(Location location) {
1178 if (mProvider != null) {
1179 long identity = Binder.clearCallingIdentity();
1180 try {
1181 ((MockProvider) mProvider).setLocation(location);
1182 } finally {
1183 Binder.restoreCallingIdentity(identity);
1184 }
1185 }
1186 }
1187
1188 @GuardedBy("mLock")
1189 public void setStatusLocked(int status, Bundle extras, long updateTime) {
1190 if (mProvider != null) {
1191 long identity = Binder.clearCallingIdentity();
1192 try {
1193 ((MockProvider) mProvider).setStatus(status, extras, updateTime);
1194 } finally {
1195 Binder.restoreCallingIdentity(identity);
1196 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001197 }
1198 }
1199 }
1200
Victoria Lease38389b62012-09-30 11:44:22 -07001201 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
1203 * location updates.
1204 */
Mike Lockwood48f17512009-04-23 09:12:08 -07001205 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -07001206 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001207 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001208 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001209
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001210 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -07001212 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001213 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
1214 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001215
gomo48f1a642017-11-10 20:35:46 -08001216 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -07001217
David Christie0b837452013-07-29 16:02:13 -07001218 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001219 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -07001220 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001221 private boolean mOpHighPowerMonitoring;
1222 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -07001223 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001225 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001226 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001229 if (listener != null) {
1230 mKey = listener.asBinder();
1231 } else {
1232 mKey = intent;
1233 }
Victoria Lease37425c32012-10-16 16:08:48 -07001234 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001235 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +00001236 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -07001237 workSource = null;
1238 }
1239 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -07001240 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -07001241
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001242 updateMonitoring(true);
1243
Victoria Lease0aa28602013-05-29 15:28:26 -07001244 // construct/configure wakelock
1245 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -07001246 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001247 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001248 }
1249 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -07001250
1251 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
1252 // only need to release it once.
1253 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 }
1255
1256 @Override
1257 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001258 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 }
1260
1261 @Override
1262 public int hashCode() {
1263 return mKey.hashCode();
1264 }
Mike Lockwood3681f262009-05-12 10:52:03 -04001265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 @Override
1267 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001268 StringBuilder s = new StringBuilder();
1269 s.append("Reciever[");
1270 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001272 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001274 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001276 for (String p : mUpdateRecords.keySet()) {
1277 s.append(" ").append(mUpdateRecords.get(p).toString());
1278 }
Wei Wangdd070f22018-06-21 11:29:40 -07001279 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001280 s.append("]");
1281 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 }
1283
David Christie15b31912013-08-13 15:54:32 -07001284 /**
1285 * Update AppOp monitoring for this receiver.
1286 *
1287 * @param allow If true receiver is currently active, if false it's been removed.
1288 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001289 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001290 if (mHideFromAppOps) {
1291 return;
1292 }
1293
David Christie15b31912013-08-13 15:54:32 -07001294 boolean requestingLocation = false;
1295 boolean requestingHighPowerLocation = false;
1296 if (allow) {
1297 // See if receiver has any enabled update records. Also note if any update records
1298 // are high power (has a high power provider with an interval under a threshold).
1299 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001300 LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
1301 if (provider == null || !provider.isUseableLocked()) {
1302 continue;
1303 }
1304
1305 requestingLocation = true;
1306 ProviderProperties properties = provider.getPropertiesLocked();
1307 if (properties != null
1308 && properties.mPowerRequirement == Criteria.POWER_HIGH
1309 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1310 requestingHighPowerLocation = true;
1311 break;
David Christie15b31912013-08-13 15:54:32 -07001312 }
1313 }
1314 }
1315
David Christie0b837452013-07-29 16:02:13 -07001316 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001317 mOpMonitoring = updateMonitoring(
1318 requestingLocation,
1319 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001320 AppOpsManager.OP_MONITOR_LOCATION);
1321
1322 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001323 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001324 mOpHighPowerMonitoring = updateMonitoring(
1325 requestingHighPowerLocation,
1326 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001327 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001328 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001329 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001330 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1331 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1332 }
David Christie0b837452013-07-29 16:02:13 -07001333 }
1334
1335 /**
1336 * Update AppOps monitoring for a single location request and op type.
1337 *
gomo48f1a642017-11-10 20:35:46 -08001338 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001339 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001340 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001341 * @return True if monitoring is on for this request/op after updating.
1342 */
1343 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1344 int op) {
1345 if (!currentlyMonitoring) {
1346 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001347 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001348 == AppOpsManager.MODE_ALLOWED;
1349 }
1350 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001351 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001352 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001353 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001354 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001355 return false;
1356 }
1357 }
1358
1359 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001360 }
1361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 public boolean isListener() {
1363 return mListener != null;
1364 }
1365
1366 public boolean isPendingIntent() {
1367 return mPendingIntent != null;
1368 }
1369
1370 public ILocationListener getListener() {
1371 if (mListener != null) {
1372 return mListener;
1373 }
1374 throw new IllegalStateException("Request for non-existent listener");
1375 }
1376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1378 if (mListener != null) {
1379 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001380 synchronized (this) {
1381 // synchronize to ensure incrementPendingBroadcastsLocked()
1382 // is called before decrementPendingBroadcasts()
1383 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001384 // call this after broadcasting so we do not increment
1385 // if we throw an exeption.
1386 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001387 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 } catch (RemoteException e) {
1389 return false;
1390 }
1391 } else {
1392 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001393 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1395 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001396 synchronized (this) {
1397 // synchronize to ensure incrementPendingBroadcastsLocked()
1398 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001399 mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001400 getResolutionPermission(mAllowedResolutionLevel),
1401 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001402 // call this after broadcasting so we do not increment
1403 // if we throw an exeption.
1404 incrementPendingBroadcastsLocked();
1405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 } catch (PendingIntent.CanceledException e) {
1407 return false;
1408 }
1409 }
1410 return true;
1411 }
1412
1413 public boolean callLocationChangedLocked(Location location) {
1414 if (mListener != null) {
1415 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001416 synchronized (this) {
1417 // synchronize to ensure incrementPendingBroadcastsLocked()
1418 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001419 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001420 // call this after broadcasting so we do not increment
1421 // if we throw an exeption.
1422 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001423 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 } catch (RemoteException e) {
1425 return false;
1426 }
1427 } else {
1428 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001429 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1430 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001432 synchronized (this) {
1433 // synchronize to ensure incrementPendingBroadcastsLocked()
1434 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001435 mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001436 getResolutionPermission(mAllowedResolutionLevel),
1437 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001438 // call this after broadcasting so we do not increment
1439 // if we throw an exeption.
1440 incrementPendingBroadcastsLocked();
1441 }
1442 } catch (PendingIntent.CanceledException e) {
1443 return false;
1444 }
1445 }
1446 return true;
1447 }
1448
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001449 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001450 // First update AppOp monitoring.
1451 // An app may get/lose location access as providers are enabled/disabled.
1452 updateMonitoring(true);
1453
Mike Lockwood48f17512009-04-23 09:12:08 -07001454 if (mListener != null) {
1455 try {
1456 synchronized (this) {
1457 // synchronize to ensure incrementPendingBroadcastsLocked()
1458 // is called before decrementPendingBroadcasts()
1459 if (enabled) {
1460 mListener.onProviderEnabled(provider);
1461 } else {
1462 mListener.onProviderDisabled(provider);
1463 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001464 // call this after broadcasting so we do not increment
1465 // if we throw an exeption.
1466 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001467 }
1468 } catch (RemoteException e) {
1469 return false;
1470 }
1471 } else {
1472 Intent providerIntent = new Intent();
1473 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1474 try {
1475 synchronized (this) {
1476 // synchronize to ensure incrementPendingBroadcastsLocked()
1477 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001478 mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001479 getResolutionPermission(mAllowedResolutionLevel),
1480 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001481 // call this after broadcasting so we do not increment
1482 // if we throw an exeption.
1483 incrementPendingBroadcastsLocked();
1484 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 } catch (PendingIntent.CanceledException e) {
1486 return false;
1487 }
1488 }
1489 return true;
1490 }
1491
Nick Pellyf1be6862012-05-15 10:53:42 -07001492 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001494 if (D) Log.d(TAG, "Location listener died");
1495
Soonil Nagarkar68257742019-01-09 19:42:34 +00001496 synchronized (mLock) {
1497 removeUpdatesLocked(this);
1498 }
1499 synchronized (this) {
1500 clearPendingBroadcastsLocked();
1501 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001502 }
1503
Nick Pellye0fd6932012-07-11 10:26:13 -07001504 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001505 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1506 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001507 synchronized (this) {
1508 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001509 }
1510 }
1511
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001512 // this must be called while synchronized by caller in a synchronized block
1513 // containing the sending of the broadcaset
1514 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001515 mPendingBroadcasts++;
1516 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001517 }
1518
1519 private void decrementPendingBroadcastsLocked() {
1520 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001521 if (mWakeLock.isHeld()) {
1522 mWakeLock.release();
1523 }
1524 }
1525 }
1526
1527 public void clearPendingBroadcastsLocked() {
1528 if (mPendingBroadcasts > 0) {
1529 mPendingBroadcasts = 0;
1530 if (mWakeLock.isHeld()) {
1531 mWakeLock.release();
1532 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001533 }
1534 }
1535 }
1536
Nick Pellye0fd6932012-07-11 10:26:13 -07001537 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001538 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001539 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001540 //the receiver list if it is not found. If it is not found then the
1541 //LocationListener was removed when it had a pending broadcast and should
1542 //not be added back.
Soonil Nagarkar68257742019-01-09 19:42:34 +00001543 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001544 IBinder binder = listener.asBinder();
1545 Receiver receiver = mReceivers.get(binder);
1546 if (receiver != null) {
1547 synchronized (receiver) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001548 // so wakelock calls will succeed
1549 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001550 try {
1551 receiver.decrementPendingBroadcastsLocked();
1552 } finally {
1553 Binder.restoreCallingIdentity(identity);
1554 }
David Christie2ff96af2014-01-30 16:09:37 -08001555 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001556 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001557 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 }
1559
Lifu Tang82f893d2016-01-21 18:15:33 -08001560 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001561 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001562 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001563 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001564 } else {
1565 return 0;
1566 }
1567 }
1568
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001569 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001570 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001571 public String getGnssHardwareModelName() {
1572 if (mGnssSystemInfoProvider != null) {
1573 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1574 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001575 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001576 }
1577 }
1578
Wyatt Rileycf879db2017-01-12 13:57:38 -08001579 private boolean hasGnssPermissions(String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001580 synchronized (mLock) {
1581 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1582 checkResolutionLevelIsSufficientForProviderUseLocked(
1583 allowedResolutionLevel,
1584 GPS_PROVIDER);
Wyatt Rileycf879db2017-01-12 13:57:38 -08001585
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001586 int pid = Binder.getCallingPid();
1587 int uid = Binder.getCallingUid();
1588 long identity = Binder.clearCallingIdentity();
1589 try {
1590 return checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1591 } finally {
1592 Binder.restoreCallingIdentity(identity);
1593 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001594 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001595 }
1596
Wyatt Rileycf879db2017-01-12 13:57:38 -08001597 @Override
1598 public int getGnssBatchSize(String packageName) {
1599 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1600 "Location Hardware permission not granted to access hardware batching");
1601
1602 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001603 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001604 } else {
1605 return 0;
1606 }
1607 }
1608
Wyatt Rileycf879db2017-01-12 13:57:38 -08001609 @Override
1610 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1611 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1612 "Location Hardware permission not granted to access hardware batching");
1613
1614 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1615 return false;
1616 }
1617
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001618 synchronized (mLock) {
1619 mGnssBatchingCallback = callback;
1620 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1621 try {
1622 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1623 } catch (RemoteException e) {
1624 // if the remote process registering the listener is already dead, just swallow the
1625 // exception and return
1626 Log.e(TAG, "Remote listener already died.", e);
1627 return false;
1628 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001629
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001630 return true;
1631 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001632 }
1633
1634 private class LinkedCallback implements IBinder.DeathRecipient {
1635 private final IBatchedLocationCallback mCallback;
1636
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001637 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001638 mCallback = callback;
1639 }
1640
1641 @NonNull
1642 public IBatchedLocationCallback getUnderlyingListener() {
1643 return mCallback;
1644 }
1645
1646 @Override
1647 public void binderDied() {
1648 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1649 stopGnssBatch();
1650 removeGnssBatchingCallback();
1651 }
1652 }
1653
Wyatt Rileycf879db2017-01-12 13:57:38 -08001654 @Override
1655 public void removeGnssBatchingCallback() {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001656 synchronized (mLock) {
1657 try {
1658 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1659 0 /* flags */);
1660 } catch (NoSuchElementException e) {
1661 // if the death callback isn't connected (it should be...), log error, swallow the
1662 // exception and return
1663 Log.e(TAG, "Couldn't unlink death callback.", e);
1664 }
1665 mGnssBatchingCallback = null;
1666 mGnssBatchingDeathCallback = null;
Wyatt Rileycf879db2017-01-12 13:57:38 -08001667 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001668 }
1669
Wyatt Rileycf879db2017-01-12 13:57:38 -08001670 @Override
1671 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1672 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1673 "Location Hardware permission not granted to access hardware batching");
1674
1675 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1676 return false;
1677 }
1678
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001679 synchronized (mLock) {
1680 if (mGnssBatchingInProgress) {
1681 // Current design does not expect multiple starts to be called repeatedly
1682 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1683 // Try to clean up anyway, and continue
1684 stopGnssBatch();
1685 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001686
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001687 mGnssBatchingInProgress = true;
1688 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1689 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001690 }
1691
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001692
Wyatt Rileycf879db2017-01-12 13:57:38 -08001693 @Override
1694 public void flushGnssBatch(String packageName) {
1695 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1696 "Location Hardware permission not granted to access hardware batching");
1697
1698 if (!hasGnssPermissions(packageName)) {
1699 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1700 return;
1701 }
1702
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001703 synchronized (mLock) {
1704 if (!mGnssBatchingInProgress) {
1705 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1706 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001707
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001708 if (mGnssBatchingProvider != null) {
1709 mGnssBatchingProvider.flush();
1710 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001711 }
1712 }
1713
Wyatt Rileycf879db2017-01-12 13:57:38 -08001714 @Override
1715 public boolean stopGnssBatch() {
1716 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1717 "Location Hardware permission not granted to access hardware batching");
1718
Soonil Nagarkar68257742019-01-09 19:42:34 +00001719 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001720 if (mGnssBatchingProvider != null) {
1721 mGnssBatchingInProgress = false;
1722 return mGnssBatchingProvider.stop();
1723 } else {
1724 return false;
1725 }
1726 }
1727 }
1728
1729 @GuardedBy("mLock")
1730 private void addProviderLocked(LocationProvider provider) {
1731 Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
1732
1733 mProviders.add(provider);
1734
1735 provider.onAllowedChangedLocked(); // allowed state may change while provider was inactive
1736 provider.onUseableChangedLocked();
1737 }
1738
1739 @GuardedBy("mLock")
1740 private void removeProviderLocked(LocationProvider provider) {
1741 if (mProviders.remove(provider)) {
1742 long identity = Binder.clearCallingIdentity();
1743 try {
1744 provider.onUseableChangedLocked();
1745 } finally {
1746 Binder.restoreCallingIdentity(identity);
1747 }
1748 }
1749 }
1750
1751 @GuardedBy("mLock")
1752 @Nullable
1753 private LocationProvider getLocationProviderLocked(String providerName) {
1754 for (LocationProvider provider : mProviders) {
1755 if (providerName.equals(provider.getName())) {
1756 return provider;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001757 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001758 }
1759
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001760 return null;
Maggie2a9409e2018-03-21 11:47:28 -07001761 }
1762
Victoria Lease37425c32012-10-16 16:08:48 -07001763 private String getResolutionPermission(int resolutionLevel) {
1764 switch (resolutionLevel) {
1765 case RESOLUTION_LEVEL_FINE:
1766 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1767 case RESOLUTION_LEVEL_COARSE:
1768 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1769 default:
1770 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001772 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001773
Victoria Lease37425c32012-10-16 16:08:48 -07001774 private int getAllowedResolutionLevel(int pid, int uid) {
1775 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001776 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001777 return RESOLUTION_LEVEL_FINE;
1778 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001779 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001780 return RESOLUTION_LEVEL_COARSE;
1781 } else {
1782 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001783 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001784 }
1785
Victoria Lease37425c32012-10-16 16:08:48 -07001786 private int getCallerAllowedResolutionLevel() {
1787 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1788 }
1789
Victoria Lease37425c32012-10-16 16:08:48 -07001790 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1791 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001792 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1793 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 }
1795
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001796 @GuardedBy("mLock")
1797 private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
1798 if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001799 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001800 return RESOLUTION_LEVEL_FINE;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001801 } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001802 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001803 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001804 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001805 for (LocationProvider lp : mProviders) {
1806 if (!lp.getName().equals(provider)) {
1807 continue;
1808 }
1809
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001810 ProviderProperties properties = lp.getPropertiesLocked();
Laurent Tu941221c2012-10-04 14:21:52 -07001811 if (properties != null) {
1812 if (properties.mRequiresSatellite) {
1813 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001814 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001815 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1816 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001817 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001818 }
1819 }
1820 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001821 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001822
Victoria Lease37425c32012-10-16 16:08:48 -07001823 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001824 }
1825
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001826 @GuardedBy("mLock")
1827 private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001828 String providerName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001829 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
Victoria Lease37425c32012-10-16 16:08:48 -07001830 if (allowedResolutionLevel < requiredResolutionLevel) {
1831 switch (requiredResolutionLevel) {
1832 case RESOLUTION_LEVEL_FINE:
1833 throw new SecurityException("\"" + providerName + "\" location provider " +
1834 "requires ACCESS_FINE_LOCATION permission.");
1835 case RESOLUTION_LEVEL_COARSE:
1836 throw new SecurityException("\"" + providerName + "\" location provider " +
1837 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1838 default:
1839 throw new SecurityException("Insufficient permission for \"" + providerName +
1840 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001841 }
1842 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001843 }
1844
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001845 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001846 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1847 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001848 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001849 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001850 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001851 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001852 }
1853 return -1;
1854 }
1855
Wei Wangb86334f2018-07-03 16:33:24 -07001856 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001857 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001858 case RESOLUTION_LEVEL_COARSE:
1859 return AppOpsManager.OPSTR_COARSE_LOCATION;
1860 case RESOLUTION_LEVEL_FINE:
1861 return AppOpsManager.OPSTR_FINE_LOCATION;
1862 case RESOLUTION_LEVEL_NONE:
1863 // The client is not allowed to get any location, so both FINE and COARSE ops will
1864 // be denied. Pick the most restrictive one to be safe.
1865 return AppOpsManager.OPSTR_FINE_LOCATION;
1866 default:
1867 // Use the most restrictive ops if not sure.
1868 return AppOpsManager.OPSTR_FINE_LOCATION;
1869 }
1870 }
1871
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001872 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001873 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001874 int op = resolutionLevelToOp(allowedResolutionLevel);
1875 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001876 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1877 return false;
1878 }
1879 }
David Christieb870dbf2015-06-22 12:42:53 -07001880
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001881 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001882 }
1883
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001884 private boolean checkLocationAccess(int pid, int uid, String packageName,
1885 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001886 int op = resolutionLevelToOp(allowedResolutionLevel);
1887 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001888 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001889 return false;
1890 }
1891 }
David Christieb870dbf2015-06-22 12:42:53 -07001892
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001893 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001894 }
1895
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001896 /**
Maggie91e630c2018-01-24 17:31:46 -08001897 * Returns all providers by name, including passive and the ones that are not permitted to
1898 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001899 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001900 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001901 public List<String> getAllProviders() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001902 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001903 ArrayList<String> providers = new ArrayList<>(mProviders.size());
Soonil Nagarkar68257742019-01-09 19:42:34 +00001904 for (LocationProvider provider : mProviders) {
1905 String name = provider.getName();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001906 if (FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001907 continue;
1908 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001909 providers.add(name);
Maggie91e630c2018-01-24 17:31:46 -08001910 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001911 return providers;
Maggie91e630c2018-01-24 17:31:46 -08001912 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 }
1914
Mike Lockwood03ca2162010-04-01 08:10:09 -07001915 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001916 * Return all providers by name, that match criteria and are optionally
1917 * enabled.
1918 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001919 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001920 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001921 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001922 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001923 synchronized (mLock) {
1924 ArrayList<String> providers = new ArrayList<>(mProviders.size());
1925 for (LocationProvider provider : mProviders) {
1926 String name = provider.getName();
1927 if (FUSED_PROVIDER.equals(name)) {
1928 continue;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001929 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001930 if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
1931 continue;
1932 }
1933 if (enabledOnly && !provider.isUseableLocked()) {
1934 continue;
1935 }
1936 if (criteria != null
1937 && !android.location.LocationProvider.propertiesMeetCriteria(
1938 name, provider.getPropertiesLocked(), criteria)) {
1939 continue;
1940 }
1941 providers.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001942 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001943 return providers;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001944 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001945 }
1946
1947 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001948 * Return the name of the best provider given a Criteria object.
1949 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001950 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001951 * has been deprecated as well. So this method now uses
1952 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001953 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001954 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001955 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001956 List<String> providers = getProviders(criteria, enabledOnly);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001957 if (providers.isEmpty()) {
1958 providers = getProviders(null, enabledOnly);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001959 }
1960
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001961 if (!providers.isEmpty()) {
1962 if (providers.contains(GPS_PROVIDER)) {
1963 return GPS_PROVIDER;
1964 } else if (providers.contains(NETWORK_PROVIDER)) {
1965 return NETWORK_PROVIDER;
1966 } else {
1967 return providers.get(0);
1968 }
1969 }
1970
Mike Lockwood03ca2162010-04-01 08:10:09 -07001971 return null;
1972 }
1973
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001974 @GuardedBy("mLock")
1975 private void updateProviderUseableLocked(LocationProvider provider) {
1976 boolean useable = provider.isUseableLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001977
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001979
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001980 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001982 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001983 if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001984 // Sends a notification message to the receiver
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001985 if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001986 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001987 deadReceivers = new ArrayList<>();
Victoria Leaseb711d572012-10-02 13:14:11 -07001988 }
1989 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 }
1993 }
1994
1995 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001996 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001997 removeUpdatesLocked(deadReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 }
1999 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002000
Soonil Nagarkar68257742019-01-09 19:42:34 +00002001 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 }
2003
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002004 @GuardedBy("mLock")
2005 private void applyRequirementsLocked(String providerName) {
2006 LocationProvider provider = getLocationProviderLocked(providerName);
2007 if (provider != null) {
2008 applyRequirementsLocked(provider);
2009 }
2010 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002011
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002012 @GuardedBy("mLock")
2013 private void applyRequirementsLocked(LocationProvider provider) {
2014 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002015 WorkSource worksource = new WorkSource();
2016 ProviderRequest providerRequest = new ProviderRequest();
2017
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002018 long backgroundThrottleInterval;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002019
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002020 long identity = Binder.clearCallingIdentity();
2021 try {
2022 backgroundThrottleInterval = Settings.Global.getLong(
2023 mContext.getContentResolver(),
2024 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
2025 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
2026 } finally {
2027 Binder.restoreCallingIdentity(identity);
2028 }
2029
2030 if (provider.isUseableLocked() && records != null && !records.isEmpty()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002031 // initialize the low power mode to true and set to false if any of the records requires
2032 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002033 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002034 if (isCurrentProfileLocked(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
David Christieb870dbf2015-06-22 12:42:53 -07002035 if (checkLocationAccess(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002036 record.mReceiver.mIdentity.mPid,
2037 record.mReceiver.mIdentity.mUid,
2038 record.mReceiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002039 record.mReceiver.mAllowedResolutionLevel)) {
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002040 LocationRequest locationRequest = record.mRealRequest;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002041 long interval = locationRequest.getInterval();
2042
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002043 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002044 if (!record.mIsForegroundUid) {
2045 interval = Math.max(interval, backgroundThrottleInterval);
2046 }
2047 if (interval != locationRequest.getInterval()) {
2048 locationRequest = new LocationRequest(locationRequest);
2049 locationRequest.setInterval(interval);
2050 }
2051 }
2052
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002053 record.mRequest = locationRequest;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002054 providerRequest.locationRequests.add(locationRequest);
gomo48f1a642017-11-10 20:35:46 -08002055 if (!locationRequest.isLowPowerMode()) {
2056 providerRequest.lowPowerMode = false;
2057 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002058 if (interval < providerRequest.interval) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002059 providerRequest.reportLocation = true;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002060 providerRequest.interval = interval;
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08002061 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002062 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002063 }
2064 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002065
2066 if (providerRequest.reportLocation) {
2067 // calculate who to blame for power
2068 // This is somewhat arbitrary. We pick a threshold interval
2069 // that is slightly higher that the minimum interval, and
2070 // spread the blame across all applications with a request
2071 // under that threshold.
2072 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
2073 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002074 if (isCurrentProfileLocked(
2075 UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002076 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07002077
2078 // Don't assign battery blame for update records whose
2079 // client has no permission to receive location data.
2080 if (!providerRequest.locationRequests.contains(locationRequest)) {
2081 continue;
2082 }
2083
Victoria Leaseb711d572012-10-02 13:14:11 -07002084 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07002085 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00002086 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07002087 worksource.add(record.mReceiver.mWorkSource);
2088 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00002089 // Assign blame to caller if there's no WorkSource associated with
2090 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07002091 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002092 record.mReceiver.mIdentity.mUid,
2093 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07002094 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002095 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002096 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 }
2099 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002100
2101 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002102 provider.setRequestLocked(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002103 }
2104
Narayan Kamath32684dd2018-01-08 17:32:51 +00002105 /**
2106 * Whether a given {@code WorkSource} associated with a Location request is valid.
2107 */
2108 private static boolean isValidWorkSource(WorkSource workSource) {
2109 if (workSource.size() > 0) {
2110 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
2111 // by tags.
2112 return workSource.getName(0) != null;
2113 } else {
2114 // For now, make sure callers have supplied an attribution tag for use with
2115 // AppOpsManager. This might be relaxed in the future.
2116 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
2117 return workChains != null && !workChains.isEmpty() &&
2118 workChains.get(0).getAttributionTag() != null;
2119 }
2120 }
2121
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002122 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002123 public String[] getBackgroundThrottlingWhitelist() {
2124 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002125 return mBackgroundThrottlePackageWhitelist.toArray(new String[0]);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002126 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002127 }
2128
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002129 @GuardedBy("mLock")
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002130 private boolean isThrottlingExemptLocked(Identity identity) {
2131 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002132 return true;
2133 }
2134
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002135 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002136 return true;
2137 }
2138
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002139 for (LocationProvider provider : mProviders) {
2140 if (identity.mPackageName.equals(provider.getPackageLocked())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002141 return true;
2142 }
2143 }
2144
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002145 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002146 }
2147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002148 private class UpdateRecord {
2149 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002150 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002151 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002152 private final Receiver mReceiver;
2153 private boolean mIsForegroundUid;
2154 private Location mLastFixBroadcast;
2155 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156
2157 /**
2158 * Note: must be constructed with lock held.
2159 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002160 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002162 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002163 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002165 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002166 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167
2168 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2169 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002170 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 mRecordsByProvider.put(provider, records);
2172 }
2173 if (!records.contains(this)) {
2174 records.add(this);
2175 }
David Christie2ff96af2014-01-30 16:09:37 -08002176
2177 // Update statistics for historical location requests by package/provider
2178 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002179 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2180 mIsForegroundUid);
2181 }
2182
2183 /**
2184 * Method to be called when record changes foreground/background
2185 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002186 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002187 mIsForegroundUid = isForeground;
2188 mRequestStatistics.updateForeground(
2189 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002190 }
2191
2192 /**
David Christie2ff96af2014-01-30 16:09:37 -08002193 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002195 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002196 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002197
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002198 // remove from mRecordsByProvider
2199 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2200 if (globalRecords != null) {
2201 globalRecords.remove(this);
2202 }
2203
2204 if (!removeReceiver) return; // the caller will handle the rest
2205
2206 // remove from Receiver#mUpdateRecords
2207 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002208 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002209
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002210 // and also remove the Receiver if it has no more update records
2211 if (receiverRecords.size() == 0) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002212 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002213 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002214 }
2215
2216 @Override
2217 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002218 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002219 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2220 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002221 + ")" + " " + mRealRequest + " "
2222 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002223 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224 }
2225
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002226 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002227 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002228 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002229 IBinder binder = listener.asBinder();
2230 Receiver receiver = mReceivers.get(binder);
2231 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002232 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2233 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002234 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002235 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002236 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002237 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002238 return null;
2239 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002240 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002241 }
2242 return receiver;
2243 }
2244
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002245 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002246 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002247 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002248 Receiver receiver = mReceivers.get(intent);
2249 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002250 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2251 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002252 mReceivers.put(intent, receiver);
2253 }
2254 return receiver;
2255 }
2256
Victoria Lease37425c32012-10-16 16:08:48 -07002257 /**
2258 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2259 * and consistency requirements.
2260 *
2261 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002262 * @return a version of request that meets the given resolution and consistency requirements
2263 * @hide
2264 */
gomo48f1a642017-11-10 20:35:46 -08002265 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2266 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002267 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002268 if (!callerHasLocationHardwarePermission) {
2269 // allow setting low power mode only for callers with location hardware permission
2270 sanitizedRequest.setLowPowerMode(false);
2271 }
Victoria Lease37425c32012-10-16 16:08:48 -07002272 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2273 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002274 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002275 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002276 break;
2277 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002278 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002279 break;
2280 }
2281 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002282 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2283 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002284 }
Victoria Lease37425c32012-10-16 16:08:48 -07002285 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2286 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002287 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002288 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002289 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002290 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002291 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002292 }
Victoria Lease37425c32012-10-16 16:08:48 -07002293 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002294 }
2295
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002296 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002297 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002298 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002299 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002300 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002301 String[] packages = mPackageManager.getPackagesForUid(uid);
2302 if (packages == null) {
2303 throw new SecurityException("invalid UID " + uid);
2304 }
2305 for (String pkg : packages) {
2306 if (packageName.equals(pkg)) return;
2307 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002308 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002309 }
2310
Nick Pellye0fd6932012-07-11 10:26:13 -07002311 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002312 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002313 PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002314 synchronized (mLock) {
2315 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2316 checkPackageName(packageName);
2317 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2318 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2319 request.getProvider());
2320 WorkSource workSource = request.getWorkSource();
2321 if (workSource != null && !workSource.isEmpty()) {
2322 mContext.enforceCallingOrSelfPermission(
2323 Manifest.permission.UPDATE_DEVICE_STATS, null);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002324 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002325 boolean hideFromAppOps = request.getHideFromAppOps();
2326 if (hideFromAppOps) {
2327 mContext.enforceCallingOrSelfPermission(
2328 Manifest.permission.UPDATE_APP_OPS_STATS, null);
2329 }
2330 boolean callerHasLocationHardwarePermission =
2331 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2332 == PERMISSION_GRANTED;
2333 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2334 allowedResolutionLevel,
2335 callerHasLocationHardwarePermission);
2336
2337 final int pid = Binder.getCallingPid();
2338 final int uid = Binder.getCallingUid();
2339
2340 long identity = Binder.clearCallingIdentity();
2341 try {
2342
2343 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2344 // a location.
2345 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
2346
2347 if (intent == null && listener == null) {
2348 throw new IllegalArgumentException("need either listener or intent");
2349 } else if (intent != null && listener != null) {
2350 throw new IllegalArgumentException(
2351 "cannot register both listener and intent");
2352 }
2353
2354 Receiver receiver;
2355 if (intent != null) {
2356 receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
2357 hideFromAppOps);
2358 } else {
2359 receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
2360 hideFromAppOps);
2361 }
2362 requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
2363 } finally {
2364 Binder.restoreCallingIdentity(identity);
2365 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002367 }
2368
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002369 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002370 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002371 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002372 // Figure out the provider. Either its explicitly request (legacy use cases), or
2373 // use the fused provider
2374 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2375 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002376 if (name == null) {
2377 throw new IllegalArgumentException("provider name must not be null");
2378 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002379
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002380 LocationProvider provider = getLocationProviderLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002381 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002382 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002383 }
2384
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002385 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002386 if (D) {
2387 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2388 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2389 + (record.mIsForegroundUid ? "foreground" : "background")
2390 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002391 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002392 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002393
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002394 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2395 if (oldRecord != null) {
2396 oldRecord.disposeLocked(false);
2397 }
2398
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002399 if (provider.isUseableLocked()) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002400 applyRequirementsLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002401 } else {
2402 // Notify the listener that updates are currently disabled
2403 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002404 }
David Christie0b837452013-07-29 16:02:13 -07002405 // Update the monitoring here just in case multiple location requests were added to the
2406 // same receiver (this request may be high power and the initial might not have been).
2407 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002408 }
2409
Nick Pellye0fd6932012-07-11 10:26:13 -07002410 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002411 public void removeUpdates(ILocationListener listener, PendingIntent intent,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002412 String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002413 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002414
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002415 int pid = Binder.getCallingPid();
2416 int uid = Binder.getCallingUid();
2417
2418 if (intent == null && listener == null) {
2419 throw new IllegalArgumentException("need either listener or intent");
2420 } else if (intent != null && listener != null) {
2421 throw new IllegalArgumentException("cannot register both listener and intent");
2422 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002423
Soonil Nagarkar68257742019-01-09 19:42:34 +00002424 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002425 Receiver receiver;
2426 if (intent != null) {
2427 receiver = getReceiverLocked(intent, pid, uid, packageName, null, false);
2428 } else {
2429 receiver = getReceiverLocked(listener, pid, uid, packageName, null, false);
2430 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002431
Soonil Nagarkar68257742019-01-09 19:42:34 +00002432 long identity = Binder.clearCallingIdentity();
2433 try {
2434 removeUpdatesLocked(receiver);
2435 } finally {
2436 Binder.restoreCallingIdentity(identity);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002437 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002438 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002439 }
2440
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002441 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002442 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002443 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002444
2445 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2446 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2447 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002448 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002450 }
2451
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002452 receiver.updateMonitoring(false);
2453
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002454 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002455 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002456 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2457 if (oldRecords != null) {
2458 // Call dispose() on the obsolete update records.
2459 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002460 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002461 record.disposeLocked(false);
2462 }
2463 // Accumulate providers
2464 providers.addAll(oldRecords.keySet());
2465 }
2466
2467 // update provider
2468 for (String provider : providers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002469 applyRequirementsLocked(provider);
2470 }
2471 }
2472
Nick Pellye0fd6932012-07-11 10:26:13 -07002473 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002474 public Location getLastLocation(LocationRequest r, String packageName) {
2475 if (D) Log.d(TAG, "getLastLocation: " + r);
2476 synchronized (mLock) {
2477 LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
2478 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2479 checkPackageName(packageName);
2480 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2481 request.getProvider());
2482 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002483
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002484 final int pid = Binder.getCallingPid();
2485 final int uid = Binder.getCallingUid();
2486 final long identity = Binder.clearCallingIdentity();
2487 try {
2488 if (mBlacklist.isBlacklisted(packageName)) {
2489 if (D) {
2490 Log.d(TAG, "not returning last loc for blacklisted app: "
2491 + packageName);
2492 }
2493 return null;
gomo48f1a642017-11-10 20:35:46 -08002494 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002495
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002496 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
2497 if (D) {
2498 Log.d(TAG, "not returning last loc for no op app: "
2499 + packageName);
2500 }
2501 return null;
gomo48f1a642017-11-10 20:35:46 -08002502 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002503
Soonil Nagarkar68257742019-01-09 19:42:34 +00002504 // Figure out the provider. Either its explicitly request (deprecated API's),
2505 // or use the fused provider
2506 String name = request.getProvider();
2507 if (name == null) name = LocationManager.FUSED_PROVIDER;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002508 LocationProvider provider = getLocationProviderLocked(name);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002509 if (provider == null) return null;
2510
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002511 // only the current user or location providers may get location this way
2512 if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isLocationProviderLocked(
2513 uid)) {
2514 return null;
2515 }
2516
2517 if (!provider.isUseableLocked()) {
2518 return null;
2519 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002520
2521 Location location;
2522 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2523 // Make sure that an app with coarse permissions can't get frequent location
2524 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2525 location = mLastLocationCoarseInterval.get(name);
2526 } else {
2527 location = mLastLocation.get(name);
2528 }
2529 if (location == null) {
2530 return null;
2531 }
2532
2533 // Don't return stale location to apps with foreground-only location permission.
2534 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002535 long locationAgeMs = SystemClock.elapsedRealtime()
2536 - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2537 if ((locationAgeMs > Settings.Global.getLong(
2538 mContext.getContentResolver(),
2539 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2540 DEFAULT_LAST_LOCATION_MAX_AGE_MS))
Soonil Nagarkar68257742019-01-09 19:42:34 +00002541 && (mAppOps.unsafeCheckOp(op, uid, packageName)
2542 == AppOpsManager.MODE_FOREGROUND)) {
2543 return null;
2544 }
2545
2546 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2547 Location noGPSLocation = location.getExtraLocation(
2548 Location.EXTRA_NO_GPS_LOCATION);
2549 if (noGPSLocation != null) {
2550 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
2551 }
2552 } else {
2553 return new Location(location);
2554 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002555 return null;
2556 } finally {
2557 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002558 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002559 }
2560 }
2561
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002562 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002563 public boolean injectLocation(Location location) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002564 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2565 "Location Hardware permission not granted to inject location");
2566 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2567 "Access Fine Location permission not granted to inject Location");
2568
2569 if (location == null) {
2570 if (D) {
2571 Log.d(TAG, "injectLocation(): called with null location");
2572 }
2573 return false;
2574 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002575
Soonil Nagarkar68257742019-01-09 19:42:34 +00002576 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002577 LocationProvider provider = getLocationProviderLocked(location.getProvider());
2578 if (provider == null || !provider.isUseableLocked()) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002579 return false;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002580 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002581
2582 // NOTE: If last location is already available, location is not injected. If
2583 // provider's normal source (like a GPS chipset) have already provided an output
2584 // there is no need to inject this location.
2585 if (mLastLocation.get(provider.getName()) != null) {
2586 return false;
2587 }
2588
2589 updateLastLocationLocked(location, provider.getName());
2590 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002591 }
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002592 }
2593
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002594 @Override
2595 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2596 String packageName) {
2597 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002598 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2599 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002600 if (intent == null) {
2601 throw new IllegalArgumentException("invalid pending intent: " + null);
Victoria Lease56e675b2012-11-05 19:25:06 -08002602 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002603 checkPackageName(packageName);
2604 synchronized (mLock) {
2605 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2606 request.getProvider());
2607 // Require that caller can manage given document
2608 boolean callerHasLocationHardwarePermission =
2609 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2610 == PERMISSION_GRANTED;
2611 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2612 allowedResolutionLevel,
2613 callerHasLocationHardwarePermission);
2614
2615 if (D) {
2616 Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
2617 }
2618
2619 // geo-fence manager uses the public location API, need to clear identity
2620 int uid = Binder.getCallingUid();
2621 // TODO: http://b/23822629
2622 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
2623 // temporary measure until geofences work for secondary users
2624 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2625 return;
2626 }
2627 long identity = Binder.clearCallingIdentity();
2628 try {
2629 mGeofenceManager.addFence(sanitizedRequest, geofence, intent,
2630 allowedResolutionLevel,
2631 uid, packageName);
2632 } finally {
2633 Binder.restoreCallingIdentity(identity);
2634 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002635 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002636 }
2637
2638 @Override
2639 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002640 if (intent == null) {
2641 throw new IllegalArgumentException("invalid pending intent: " + null);
2642 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002643 checkPackageName(packageName);
2644
2645 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2646
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002647 // geo-fence manager uses the public location API, need to clear identity
2648 long identity = Binder.clearCallingIdentity();
2649 try {
2650 mGeofenceManager.removeFence(geofence, intent);
2651 } finally {
2652 Binder.restoreCallingIdentity(identity);
2653 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002654 }
2655
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002656 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002657 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002658 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002659 return false;
2660 }
2661
Anil Admal75b9fd62018-11-28 11:22:50 -08002662 // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
2663 // measurements listeners.
2664 return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002665 }
2666
Nick Pellye0fd6932012-07-11 10:26:13 -07002667 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002668 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002669 mGnssStatusProvider.removeListener(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002670 }
2671
Nick Pellye0fd6932012-07-11 10:26:13 -07002672 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002673 public boolean addGnssMeasurementsListener(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002674 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002675 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002676 return false;
2677 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002678
Soonil Nagarkar68257742019-01-09 19:42:34 +00002679 synchronized (mLock) {
2680 Identity callerIdentity
2681 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002682 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002683 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002684 long identity = Binder.clearCallingIdentity();
2685 try {
2686 if (isThrottlingExemptLocked(callerIdentity)
2687 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002688 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002689 return mGnssMeasurementsProvider.addListener(listener,
2690 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002691 }
2692 } finally {
2693 Binder.restoreCallingIdentity(identity);
2694 }
2695
2696 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002697 }
destradaaea8a8a62014-06-23 18:19:03 -07002698 }
2699
2700 @Override
gomo226b7b72018-12-12 16:49:39 -08002701 public void injectGnssMeasurementCorrections(
2702 GnssMeasurementCorrections measurementCorrections, String packageName) {
2703 mContext.enforceCallingPermission(
2704 android.Manifest.permission.LOCATION_HARDWARE,
2705 "Location Hardware permission not granted to inject GNSS measurement corrections.");
2706 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2707 mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
2708 } else {
2709 Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
2710 }
2711 }
2712
2713 @Override
2714 public int getGnssCapabilities(String packageName) {
2715 mContext.enforceCallingPermission(
2716 android.Manifest.permission.LOCATION_HARDWARE,
2717 "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
2718 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2719 return -1;
2720 }
2721 return mGnssMeasurementsProvider.getGnssCapabilities();
2722 }
2723
2724 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002725 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002726 if (mGnssMeasurementsProvider == null) {
2727 return;
2728 }
2729
Soonil Nagarkar68257742019-01-09 19:42:34 +00002730 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002731 mGnssMeasurementsListeners.remove(listener.asBinder());
2732 mGnssMeasurementsProvider.removeListener(listener);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002733 }
destradaaea8a8a62014-06-23 18:19:03 -07002734 }
2735
2736 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002737 public boolean addGnssNavigationMessageListener(
2738 IGnssNavigationMessageListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002739 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002740 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002741 return false;
2742 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002743
Soonil Nagarkar68257742019-01-09 19:42:34 +00002744 synchronized (mLock) {
2745 Identity callerIdentity
2746 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002747
Anil Admal75b9fd62018-11-28 11:22:50 -08002748 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002749 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002750 long identity = Binder.clearCallingIdentity();
2751 try {
2752 if (isThrottlingExemptLocked(callerIdentity)
2753 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002754 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002755 return mGnssNavigationMessageProvider.addListener(listener,
2756 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002757 }
2758 } finally {
2759 Binder.restoreCallingIdentity(identity);
2760 }
2761
2762 return true;
Wei Liu5241a4c2015-05-11 14:00:36 -07002763 }
destradaa4b3e3932014-07-21 18:01:47 -07002764 }
2765
2766 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002767 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2768 if (mGnssNavigationMessageProvider != null) {
2769 synchronized (mLock) {
2770 mGnssNavigationMessageListeners.remove(listener.asBinder());
2771 mGnssNavigationMessageProvider.removeListener(listener);
2772 }
2773 }
2774 }
2775
2776 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002777 public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
2778 if (providerName == null) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002779 // throw NullPointerException to remain compatible with previous implementation
2780 throw new NullPointerException();
2781 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002782 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002783 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2784 providerName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002785
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002786 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
2787 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
2788 != PERMISSION_GRANTED)) {
2789 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2790 }
2791
2792 LocationProvider provider = getLocationProviderLocked(providerName);
2793 if (provider != null) {
2794 provider.sendExtraCommandLocked(command, extras);
2795 }
2796
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002797 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002798 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002799 }
2800
Nick Pellye0fd6932012-07-11 10:26:13 -07002801 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002802 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002803 if (Binder.getCallingUid() != Process.myUid()) {
2804 throw new SecurityException(
2805 "calling sendNiResponse from outside of the system is not allowed");
2806 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002807 try {
2808 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002809 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002810 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002811 return false;
2812 }
2813 }
2814
Nick Pellye0fd6932012-07-11 10:26:13 -07002815 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002816 public ProviderProperties getProviderProperties(String providerName) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002817 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002818 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2819 providerName);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002820
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002821 LocationProvider provider = getLocationProviderLocked(providerName);
2822 if (provider == null) {
2823 return null;
2824 }
2825 return provider.getPropertiesLocked();
2826 }
Jason Monkb71218a2015-06-17 14:44:39 -04002827 }
2828
Wei Wang980b7c22018-12-06 17:53:00 -08002829 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002830 public String getNetworkProviderPackage() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002831 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002832 LocationProvider provider = getLocationProviderLocked(NETWORK_PROVIDER);
2833 if (provider == null) {
2834 return null;
2835 }
2836 return provider.getPackageLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +00002837 }
Maggie2a9409e2018-03-21 11:47:28 -07002838 }
2839
Maggie2a9409e2018-03-21 11:47:28 -07002840 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002841 public void setLocationControllerExtraPackage(String packageName) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002842 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2843 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002844 synchronized (mLock) {
2845 mLocationControllerExtraPackage = packageName;
2846 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002847 }
2848
2849 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002850 public String getLocationControllerExtraPackage() {
2851 synchronized (mLock) {
2852 return mLocationControllerExtraPackage;
2853 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002854 }
2855
2856 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002857 public void setLocationControllerExtraPackageEnabled(boolean enabled) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002858 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2859 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002860 synchronized (mLock) {
2861 mLocationControllerExtraPackageEnabled = enabled;
2862 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002863 }
2864
2865 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002866 public boolean isLocationControllerExtraPackageEnabled() {
2867 synchronized (mLock) {
2868 return mLocationControllerExtraPackageEnabled
2869 && (mLocationControllerExtraPackage != null);
2870 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002871 }
2872
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002873 private boolean isLocationEnabled() {
2874 return isLocationEnabledForUser(mCurrentUserId);
2875 }
2876
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002877 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002878 public boolean isLocationEnabledForUser(int userId) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002879 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002880 if (UserHandle.getCallingUserId() != userId) {
2881 mContext.enforceCallingOrSelfPermission(
2882 Manifest.permission.INTERACT_ACROSS_USERS,
2883 "Requires INTERACT_ACROSS_USERS permission");
2884 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002885
Soonil Nagarkar68257742019-01-09 19:42:34 +00002886 long identity = Binder.clearCallingIdentity();
2887 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002888 boolean enabled;
2889 try {
2890 enabled = Settings.Secure.getIntForUser(
2891 mContext.getContentResolver(),
2892 Settings.Secure.LOCATION_MODE,
2893 userId) != Settings.Secure.LOCATION_MODE_OFF;
2894 } catch (Settings.SettingNotFoundException e) {
2895 // OS upgrade case where mode isn't set yet
2896 enabled = !TextUtils.isEmpty(Settings.Secure.getStringForUser(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002897 mContext.getContentResolver(),
2898 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002899 userId));
2900
2901 try {
2902 Settings.Secure.putIntForUser(
2903 mContext.getContentResolver(),
2904 Settings.Secure.LOCATION_MODE,
2905 enabled
2906 ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
2907 : Settings.Secure.LOCATION_MODE_OFF,
2908 userId);
2909 } catch (RuntimeException ex) {
2910 // any problem with writing should not be propagated
2911 Slog.e(TAG, "error updating location mode", ex);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002912 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002913 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002914 return enabled;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002915 } finally {
2916 Binder.restoreCallingIdentity(identity);
2917 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002918 }
2919
Maggie2a9409e2018-03-21 11:47:28 -07002920 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002921 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002922 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002923 if (UserHandle.getCallingUserId() != userId) {
2924 mContext.enforceCallingOrSelfPermission(
2925 Manifest.permission.INTERACT_ACROSS_USERS,
2926 "Requires INTERACT_ACROSS_USERS permission");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002927 }
2928
Maggie2a9409e2018-03-21 11:47:28 -07002929 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2930 // so we discourage its use
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002931 if (FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002932
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002933 synchronized (mLock) {
2934 LocationProvider provider = getLocationProviderLocked(providerName);
2935 return provider != null && provider.isUseableForUserLocked(userId);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002936 }
Maggie2a9409e2018-03-21 11:47:28 -07002937 }
2938
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002939 @GuardedBy("mLock")
2940 private boolean isLocationProviderLocked(int uid) {
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002941 if (uid == Process.SYSTEM_UID) {
2942 return true;
2943 }
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002944
David Christie1f141c12014-05-14 15:11:15 -07002945 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2946 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002947 return false;
2948 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002949 for (LocationProvider provider : mProviders) {
2950 String packageName = provider.getPackageLocked();
2951 if (packageName == null) {
2952 continue;
2953 }
2954 if (ArrayUtils.contains(packageNames, packageName)) {
David Christie1f141c12014-05-14 15:11:15 -07002955 return true;
2956 }
2957 }
2958 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002959 }
2960
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002961 @GuardedBy("mLock")
2962 private static boolean shouldBroadcastSafeLocked(
Laurent Tu75defb62012-11-01 16:21:52 -07002963 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 // Always broadcast the first update
2965 if (lastLoc == null) {
2966 return true;
2967 }
2968
Nick Pellyf1be6862012-05-15 10:53:42 -07002969 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002970 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002971 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2972 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002973 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002974 return false;
2975 }
2976
2977 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002978 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002979 if (minDistance > 0.0) {
2980 if (loc.distanceTo(lastLoc) <= minDistance) {
2981 return false;
2982 }
2983 }
2984
Laurent Tu75defb62012-11-01 16:21:52 -07002985 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002986 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002987 return false;
2988 }
2989
2990 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002991 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002992 }
2993
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002994 @GuardedBy("mLock")
2995 private void handleLocationChangedLocked(Location location, LocationProvider provider) {
2996 if (!mProviders.contains(provider)) {
2997 return;
2998 }
2999 if (!location.isComplete()) {
3000 Log.w(TAG, "Dropping incomplete location: " + location);
3001 return;
3002 }
3003
3004 if (!provider.isPassiveLocked()) {
3005 // notify passive provider of the new location
3006 mPassiveProvider.updateLocation(location);
3007 }
3008
Soonil Nagarkar68257742019-01-09 19:42:34 +00003009 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003010 long now = SystemClock.elapsedRealtime();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003011 updateLastLocationLocked(location, provider.getName());
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003012 // mLastLocation should have been updated from the updateLastLocationLocked call above.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003013 Location lastLocation = mLastLocation.get(provider.getName());
Mike Lockwood4e50b782009-04-03 08:24:43 -07003014 if (lastLocation == null) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003015 Log.e(TAG, "handleLocationChangedLocked() updateLastLocation failed");
3016 return;
Mike Lockwood4e50b782009-04-03 08:24:43 -07003017 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003018
David Christie1b9b7b12013-04-15 15:31:11 -07003019 // Update last known coarse interval location if enough time has passed.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003020 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(provider.getName());
David Christie1b9b7b12013-04-15 15:31:11 -07003021 if (lastLocationCoarseInterval == null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003022 lastLocationCoarseInterval = new Location(location);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003023 mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
David Christie1b9b7b12013-04-15 15:31:11 -07003024 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003025 long timeDiffNanos = location.getElapsedRealtimeNanos()
David Christie1b9b7b12013-04-15 15:31:11 -07003026 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
3027 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003028 lastLocationCoarseInterval.set(location);
David Christie1b9b7b12013-04-15 15:31:11 -07003029 }
3030 // Don't ever return a coarse location that is more recent than the allowed update
3031 // interval (i.e. don't allow an app to keep registering and unregistering for
3032 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003033 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07003034 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3035
Laurent Tu60ec50a2012-10-04 17:00:10 -07003036 // Skip if there are no UpdateRecords for this provider.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003037 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Laurent Tu60ec50a2012-10-04 17:00:10 -07003038 if (records == null || records.size() == 0) return;
3039
Victoria Lease09016ab2012-09-16 12:33:15 -07003040 // Fetch coarse location
3041 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07003042 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003043 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
3044 }
3045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003046 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003047 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07003048
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003049 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003050 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003051 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003052 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003053
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003054 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003055 if (!isCurrentProfileLocked(receiverUserId)
3056 && !isLocationProviderLocked(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003057 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003058 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003059 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003060 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003061 }
3062 continue;
3063 }
3064
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003065 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003066 if (D) {
3067 Log.d(TAG, "skipping loc update for blacklisted app: " +
3068 receiver.mIdentity.mPackageName);
3069 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003070 continue;
3071 }
3072
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003073 if (!reportLocationAccessNoThrow(
3074 receiver.mIdentity.mPid,
3075 receiver.mIdentity.mUid,
3076 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003077 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003078 if (D) {
3079 Log.d(TAG, "skipping loc update for no op app: " +
3080 receiver.mIdentity.mPackageName);
3081 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003082 continue;
3083 }
3084
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003085 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003086 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3087 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003088 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07003089 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003090 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003091 if (notifyLocation != null) {
3092 Location lastLoc = r.mLastFixBroadcast;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003093 if ((lastLoc == null)
3094 || shouldBroadcastSafeLocked(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003095 if (lastLoc == null) {
3096 lastLoc = new Location(notifyLocation);
3097 r.mLastFixBroadcast = lastLoc;
3098 } else {
3099 lastLoc.set(notifyLocation);
3100 }
3101 if (!receiver.callLocationChangedLocked(notifyLocation)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003102 Slog.w(TAG, "RemoteException calling onLocationChanged on "
3103 + receiver);
Victoria Lease09016ab2012-09-16 12:33:15 -07003104 receiverDead = true;
3105 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003106 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003107 }
3108 }
3109
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003110 // TODO: location provider status callbacks have been disabled and deprecated, and are
3111 // guarded behind this setting now. should be removed completely post-Q
3112 if (Settings.Global.getInt(mContext.getContentResolver(),
3113 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003114 long newStatusUpdateTime = provider.getStatusUpdateTimeLocked();
3115 Bundle extras = new Bundle();
3116 int status = provider.getStatusLocked(extras);
3117
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003118 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3119 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003120 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003121
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003122 r.mLastStatusBroadcast = newStatusUpdateTime;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003123 if (!receiver.callStatusChangedLocked(provider.getName(), status, extras)) {
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003124 receiverDead = true;
3125 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3126 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003127 }
3128 }
3129
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003130 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003131 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003132 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003133 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003134 }
3135 deadUpdateRecords.add(r);
3136 }
3137 // track dead receivers
3138 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003139 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003140 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003141 }
3142 if (!deadReceivers.contains(receiver)) {
3143 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003144 }
3145 }
3146 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003147
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003148 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003149 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003150 for (Receiver receiver : deadReceivers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003151 removeUpdatesLocked(receiver);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003152 }
3153 }
3154 if (deadUpdateRecords != null) {
3155 for (UpdateRecord r : deadUpdateRecords) {
3156 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003158 applyRequirementsLocked(provider);
Victoria Lease8b38b292012-12-04 15:04:43 -08003159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003160 }
3161
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003162 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00003163 private void updateLastLocationLocked(Location location, String provider) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003164 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3165 Location lastNoGPSLocation;
3166 Location lastLocation = mLastLocation.get(provider);
3167 if (lastLocation == null) {
3168 lastLocation = new Location(provider);
3169 mLastLocation.put(provider, lastLocation);
3170 } else {
3171 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3172 if (noGPSLocation == null && lastNoGPSLocation != null) {
3173 // New location has no no-GPS location: adopt last no-GPS location. This is set
3174 // directly into location because we do not want to notify COARSE clients.
3175 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3176 }
3177 }
3178 lastLocation.set(location);
3179 }
3180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003181 // Geocoder
3182
Nick Pellye0fd6932012-07-11 10:26:13 -07003183 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003184 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003185 return mGeocodeProvider != null;
3186 }
3187
Nick Pellye0fd6932012-07-11 10:26:13 -07003188 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003189 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003190 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003191 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003192 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3193 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003195 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196 }
3197
Mike Lockwooda55c3212009-04-15 11:10:11 -04003198
Nick Pellye0fd6932012-07-11 10:26:13 -07003199 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003200 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003201 double lowerLeftLatitude, double lowerLeftLongitude,
3202 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003203 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003204
3205 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003206 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3207 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3208 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003209 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003210 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003211 }
3212
3213 // Mock Providers
3214
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003215 private boolean canCallerAccessMockLocation(String opPackageName) {
3216 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3217 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003218 }
3219
Nick Pellye0fd6932012-07-11 10:26:13 -07003220 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003221 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003222 if (!canCallerAccessMockLocation(opPackageName)) {
3223 return;
3224 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003226 if (PASSIVE_PROVIDER.equals(name)) {
Mike Lockwooda4903f22010-02-17 06:42:23 -05003227 throw new IllegalArgumentException("Cannot mock the passive location provider");
3228 }
3229
Soonil Nagarkar68257742019-01-09 19:42:34 +00003230 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003231 long identity = Binder.clearCallingIdentity();
3232 try {
3233 LocationProvider oldProvider = getLocationProviderLocked(name);
3234 if (oldProvider != null) {
3235 if (oldProvider.isMock()) {
3236 throw new IllegalArgumentException(
3237 "Provider \"" + name + "\" already exists");
3238 }
3239
3240 removeProviderLocked(oldProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003241 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003242
3243 MockLocationProvider mockProviderManager = new MockLocationProvider(name);
3244 addProviderLocked(mockProviderManager);
3245 mockProviderManager.attachLocked(new MockProvider(mockProviderManager, properties));
3246 } finally {
3247 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003248 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003249 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003250 }
3251
Nick Pellye0fd6932012-07-11 10:26:13 -07003252 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003253 public void removeTestProvider(String name, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003254 if (!canCallerAccessMockLocation(opPackageName)) {
3255 return;
3256 }
3257
Soonil Nagarkar68257742019-01-09 19:42:34 +00003258 synchronized (mLock) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003259 long identity = Binder.clearCallingIdentity();
3260 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003261 LocationProvider testProvider = getLocationProviderLocked(name);
3262 if (testProvider == null || !testProvider.isMock()) {
3263 throw new IllegalArgumentException("Provider \"" + name + "\" unknown");
3264 }
3265
3266 removeProviderLocked(testProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003267
Soonil Nagarkar68257742019-01-09 19:42:34 +00003268 // reinstate real provider if available
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003269 LocationProvider realProvider = null;
3270 for (LocationProvider provider : mRealProviders) {
3271 if (name.equals(provider.getName())) {
3272 realProvider = provider;
3273 break;
3274 }
3275 }
3276
Soonil Nagarkar68257742019-01-09 19:42:34 +00003277 if (realProvider != null) {
3278 addProviderLocked(realProvider);
3279 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003280 } finally {
3281 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003282 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003284 }
3285
Nick Pellye0fd6932012-07-11 10:26:13 -07003286 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003287 public void setTestProviderLocation(String providerName, Location location,
Soonil Nagarkar68257742019-01-09 19:42:34 +00003288 String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003289 if (!canCallerAccessMockLocation(opPackageName)) {
3290 return;
3291 }
3292
Soonil Nagarkar68257742019-01-09 19:42:34 +00003293 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003294 LocationProvider testProvider = getLocationProviderLocked(providerName);
3295 if (testProvider == null || !testProvider.isMock()) {
3296 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003297 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003298
3299 String locationProvider = location.getProvider();
3300 if (!TextUtils.isEmpty(locationProvider) && !providerName.equals(locationProvider)) {
3301 // The location has an explicit provider that is different from the mock
3302 // provider name. The caller may be trying to fool us via b/33091107.
3303 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3304 providerName + "!=" + location.getProvider());
3305 }
3306
3307 ((MockLocationProvider) testProvider).setLocationLocked(location);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003308 }
3309 }
3310
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003311 @Override
3312 public void setTestProviderEnabled(String providerName, boolean enabled, String opPackageName) {
3313 if (!canCallerAccessMockLocation(opPackageName)) {
3314 return;
3315 }
3316
3317 synchronized (mLock) {
3318 LocationProvider testProvider = getLocationProviderLocked(providerName);
3319 if (testProvider == null || !testProvider.isMock()) {
3320 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3321 }
3322
3323 ((MockLocationProvider) testProvider).setEnabledLocked(enabled);
3324 }
3325 }
3326
3327 @Override
3328 public void setTestProviderStatus(String providerName, int status, Bundle extras,
3329 long updateTime, String opPackageName) {
3330 if (!canCallerAccessMockLocation(opPackageName)) {
3331 return;
3332 }
3333
3334 synchronized (mLock) {
3335 LocationProvider testProvider = getLocationProviderLocked(providerName);
3336 if (testProvider == null || !testProvider.isMock()) {
3337 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3338 }
3339
3340 ((MockLocationProvider) testProvider).setStatusLocked(status, extras, updateTime);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003341 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003342 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003343
3344 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003345 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003346 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003347
Soonil Nagarkar68257742019-01-09 19:42:34 +00003348 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003349 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3350 if (mGnssMetricsProvider != null) {
3351 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3352 }
3353 return;
3354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003355 pw.println("Current Location Manager state:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003356 pw.println(" Location Mode: " + isLocationEnabled());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003357 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003358 for (Receiver receiver : mReceivers.values()) {
3359 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003360 }
David Christie2ff96af2014-01-30 16:09:37 -08003361 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003362 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3363 pw.println(" " + entry.getKey() + ":");
3364 for (UpdateRecord record : entry.getValue()) {
3365 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003366 }
3367 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003368 pw.println(" Active GnssMeasurement Listeners:");
3369 for (Identity identity : mGnssMeasurementsListeners.values()) {
3370 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3371 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3372 }
3373 pw.println(" Active GnssNavigationMessage Listeners:");
3374 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3375 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3376 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3377 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003378 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003379 for (LocationProvider provider : mProviders) {
3380 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003381 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003382 + ((LocationProviderProxy) provider.mProvider)
3383 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003384 }
3385 }
David Christie2ff96af2014-01-30 16:09:37 -08003386 pw.println(" Historical Records by Provider:");
3387 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3388 : mRequestStatistics.statistics.entrySet()) {
3389 PackageProviderKey key = entry.getKey();
3390 PackageStatistics stats = entry.getValue();
3391 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3392 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003393 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003394 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3395 String provider = entry.getKey();
3396 Location location = entry.getValue();
3397 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003398 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003399
David Christie1b9b7b12013-04-15 15:31:11 -07003400 pw.println(" Last Known Locations Coarse Intervals:");
3401 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3402 String provider = entry.getKey();
3403 Location location = entry.getValue();
3404 pw.println(" " + provider + ": " + location);
3405 }
3406
Nick Pellye0fd6932012-07-11 10:26:13 -07003407 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003408
Nick Pelly4035f5a2012-08-17 14:43:49 -07003409 pw.append(" ");
3410 mBlacklist.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003411
Wei Wang980b7c22018-12-06 17:53:00 -08003412 if (mLocationControllerExtraPackage != null) {
3413 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
3414 + " enabled: " + mLocationControllerExtraPackageEnabled);
3415 }
3416
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003417 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3418 pw.println(" Throttling Whitelisted Packages:");
3419 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3420 pw.println(" " + packageName);
3421 }
3422 }
3423
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003424 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003425 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003426
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003427 if (args.length > 0 && "short".equals(args[0])) {
3428 return;
3429 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003430 for (LocationProvider provider : mProviders) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003431 provider.dumpLocked(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003432 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003433 if (mGnssBatchingInProgress) {
3434 pw.println(" GNSS batching in progress");
3435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 }
3437 }
3438}