blob: b3a0f643ba4bc36133fbadf58186607094045346 [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;
Brian Duddiecfa5b5b2019-01-22 18:01:40 +000049import android.hardware.location.ActivityRecognitionHardware;
Maggieaa080f92018-01-04 15:35:11 -080050import 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;
Maggieaa080f92018-01-04 15:35:11 -080070import android.os.PowerManager;
71import android.os.Process;
72import android.os.RemoteException;
73import android.os.SystemClock;
74import android.os.UserHandle;
75import android.os.UserManager;
76import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000077import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080078import android.provider.Settings;
79import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080080import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080081import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080082import android.util.EventLog;
83import android.util.Log;
84import android.util.Slog;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -070085
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080086import com.android.internal.annotations.GuardedBy;
destradaaea8a8a62014-06-23 18:19:03 -070087import com.android.internal.content.PackageMonitor;
88import com.android.internal.location.ProviderProperties;
89import com.android.internal.location.ProviderRequest;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070090import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060091import com.android.internal.util.DumpUtils;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080092import com.android.internal.util.Preconditions;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070093import com.android.server.location.AbstractLocationProvider;
Brian Duddiecfa5b5b2019-01-22 18:01:40 +000094import com.android.server.location.ActivityRecognitionProxy;
destradaaea8a8a62014-06-23 18:19:03 -070095import com.android.server.location.GeocoderProxy;
96import com.android.server.location.GeofenceManager;
97import com.android.server.location.GeofenceProxy;
Yu-Han Yang3557cc72018-03-21 12:48:36 -070098import com.android.server.location.GnssBatchingProvider;
Lifu Tang818aa2c2016-02-01 01:52:00 -080099import com.android.server.location.GnssLocationProvider;
100import com.android.server.location.GnssMeasurementsProvider;
101import com.android.server.location.GnssNavigationMessageProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800102import com.android.server.location.GnssStatusListenerHelper;
destradaaea8a8a62014-06-23 18:19:03 -0700103import com.android.server.location.LocationBlacklist;
104import com.android.server.location.LocationFudger;
destradaaea8a8a62014-06-23 18:19:03 -0700105import com.android.server.location.LocationProviderProxy;
106import com.android.server.location.LocationRequestStatistics;
107import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
108import com.android.server.location.LocationRequestStatistics.PackageStatistics;
109import com.android.server.location.MockProvider;
110import com.android.server.location.PassiveProvider;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -0700111
Mike Lockwood43e33f22010-03-26 10:41:48 -0400112import java.io.FileDescriptor;
113import java.io.PrintWriter;
114import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700115import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400116import java.util.HashMap;
117import java.util.HashSet;
118import java.util.List;
119import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800120import java.util.Map.Entry;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800121import java.util.NoSuchElementException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122
123/**
124 * The service class that manages LocationProviders and issues location
125 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800127public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800129 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700130
Olivier Gaillard7a222662017-11-20 16:07:24 +0000131 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
Victoria Lease37425c32012-10-16 16:08:48 -0700133 // Location resolution level: no location data whatsoever
134 private static final int RESOLUTION_LEVEL_NONE = 0;
135 // Location resolution level: coarse location data only
136 private static final int RESOLUTION_LEVEL_COARSE = 1;
137 // Location resolution level: fine location data
138 private static final int RESOLUTION_LEVEL_FINE = 2;
139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700141 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700142
143 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700144 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700145 private static final String FUSED_LOCATION_SERVICE_ACTION =
146 "com.android.location.service.FusedLocationProvider";
147
David Christie1b9b7b12013-04-15 15:31:11 -0700148 private static final long NANOS_PER_MILLI = 1000000L;
149
David Christie0b837452013-07-29 16:02:13 -0700150 // The maximum interval a location request can have and still be considered "high power".
151 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
152
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700153 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800154 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700155
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800156 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800157 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800158
Wei Wangdd070f22018-06-21 11:29:40 -0700159 // Default value for maximum age of last location returned to applications with foreground-only
160 // location permissions.
161 private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
162
Nick Pellyf1be6862012-05-15 10:53:42 -0700163 // Location Providers may sometimes deliver location updates
164 // slightly faster that requested - provide grace period so
165 // we don't unnecessarily filter events that are otherwise on
166 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700168
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700169 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
170
Soonil Nagarkar68257742019-01-09 19:42:34 +0000171 private final Object mLock = new Object();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800172 private final Context mContext;
173 private final Handler mHandler;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800175 private AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700176 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700177 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800178 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700179 private UserManager mUserManager;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800180
181 private GeofenceManager mGeofenceManager;
182 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 private GeocoderProxy mGeocodeProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800184 private GnssStatusListenerHelper mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 private INetInitiatedListener mNetInitiatedListener;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700186 private PassiveProvider mPassiveProvider; // track passive provider for special cases
187 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800188 private GnssMeasurementsProvider mGnssMeasurementsProvider;
189 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800190 @GuardedBy("mLock")
Wei Wang980b7c22018-12-06 17:53:00 -0800191 private String mLocationControllerExtraPackage;
192 private boolean mLocationControllerExtraPackageEnabled;
Wei Liu5241a4c2015-05-11 14:00:36 -0700193 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700194
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800195 // list of currently active providers
196 @GuardedBy("mLock")
197 private final ArrayList<LocationProvider> mProviders = new ArrayList<>();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000198
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800199 // list of non-mock providers, so that when mock providers replace real providers, they can be
200 // later re-replaced
201 @GuardedBy("mLock")
202 private final ArrayList<LocationProvider> mRealProviders = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800204 @GuardedBy("mLock")
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800205 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700206 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800207 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700208
David Christie2ff96af2014-01-30 16:09:37 -0800209 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
210
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700211 // mapping from provider name to last known location
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800212 @GuardedBy("mLock")
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800213 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
David Christie1b9b7b12013-04-15 15:31:11 -0700215 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
216 // locations stored here are not fudged for coarse permissions.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800217 @GuardedBy("mLock")
David Christie1b9b7b12013-04-15 15:31:11 -0700218 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800219 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700220
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800221 private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800222
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800223 @GuardedBy("mLock")
Wyatt Riley11cc7492018-01-17 08:48:27 -0800224 private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800225
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800226 @GuardedBy("mLock")
Wyatt Riley11cc7492018-01-17 08:48:27 -0800227 private final ArrayMap<IBinder, Identity>
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800228 mGnssNavigationMessageListeners = new ArrayMap<>();
229
Victoria Lease38389b62012-09-30 11:44:22 -0700230 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700231 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800232 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700233
Lifu Tang9363b942016-02-16 18:07:00 -0800234 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800235
Siddharth Raybb608c82017-03-16 11:33:34 -0700236 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700237
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700238 private GnssBatchingProvider mGnssBatchingProvider;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800239 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800240 private IBatchedLocationCallback mGnssBatchingCallback;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800241 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800242 private LinkedCallback mGnssBatchingDeathCallback;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800243 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800244 private boolean mGnssBatchingInProgress = false;
245
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700246 public LocationManagerService(Context context) {
247 super();
248 mContext = context;
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -0800249 mHandler = FgThread.getHandler();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800250
Svet Ganovadc1cf42015-06-15 16:36:24 -0700251 // Let the package manager query which are the default location
252 // providers as they get certain permissions granted by default.
253 PackageManagerInternal packageManagerInternal = LocalServices.getService(
254 PackageManagerInternal.class);
255 packageManagerInternal.setLocationPackagesProvider(
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700256 userId -> mContext.getResources().getStringArray(
257 com.android.internal.R.array.config_locationProviderPackageNames));
Wei Wangffb94e62019-01-14 00:05:45 -0800258 packageManagerInternal.setLocationExtraPackagesProvider(
259 userId -> mContext.getResources().getStringArray(
260 com.android.internal.R.array.config_locationExtraPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700261
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700262 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700263 }
264
Svetoslav Ganova0027152013-06-25 14:59:53 -0700265 public void systemRunning() {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000266 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800267 initializeLocked();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800268 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800269 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700270
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800271 @GuardedBy("mLock")
272 private void initializeLocked() {
273 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
274 mPackageManager = mContext.getPackageManager();
275 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
276 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
277 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
278
279 mLocationFudger = new LocationFudger(mContext, mHandler);
280 mBlacklist = new LocationBlacklist(mContext, mHandler);
281 mBlacklist.init();
282 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
283
284 // prepare providers
285 initializeProvidersLocked();
286
287 // add listeners
288 mAppOps.startWatchingMode(
289 AppOpsManager.OP_COARSE_LOCATION,
290 null,
291 AppOpsManager.WATCH_FOREGROUND_CHANGES,
292 new AppOpsManager.OnOpChangedInternalListener() {
293 public void onOpChanged(int op, String packageName) {
294 synchronized (mLock) {
295 onAppOpChangedLocked();
296 }
297 }
298 });
299 mPackageManager.addOnPermissionsChangeListener(
300 uid -> {
301 synchronized (mLock) {
302 onPermissionsChangedLocked();
303 }
304 });
305
306 mActivityManager.addOnUidImportanceListener(
307 (uid, importance) -> {
308 synchronized (mLock) {
309 onUidImportanceChangedLocked(uid, importance);
310 }
311 },
312 FOREGROUND_IMPORTANCE_CUTOFF);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700313 mContext.getContentResolver().registerContentObserver(
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800314 Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), true,
315 new ContentObserver(mHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800316 @Override
317 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000318 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800319 onLocationModeChangedLocked(true);
320 }
321 }
322 }, UserHandle.USER_ALL);
323 mContext.getContentResolver().registerContentObserver(
324 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
325 new ContentObserver(mHandler) {
326 @Override
327 public void onChange(boolean selfChange) {
328 synchronized (mLock) {
329 onProviderAllowedChangedLocked(true);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000330 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800331 }
332 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800333 mContext.getContentResolver().registerContentObserver(
334 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
335 true,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800336 new ContentObserver(mHandler) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800337 @Override
338 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000339 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800340 onBackgroundThrottleIntervalChangedLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000341 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800342 }
343 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800344 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800345 Settings.Global.getUriFor(
346 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
347 true,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800348 new ContentObserver(mHandler) {
gomo48f1a642017-11-10 20:35:46 -0800349 @Override
350 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000351 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800352 onBackgroundThrottleWhitelistChangedLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000353 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800354 }
gomo48f1a642017-11-10 20:35:46 -0800355 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700356
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800357 new PackageMonitor() {
358 @Override
359 public void onPackageDisappeared(String packageName, int reason) {
360 synchronized (mLock) {
361 LocationManagerService.this.onPackageDisappearedLocked(packageName);
362 }
363 }
364 }.register(mContext, mHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700365
Victoria Lease38389b62012-09-30 11:44:22 -0700366 IntentFilter intentFilter = new IntentFilter();
367 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700368 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
369 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700370
371 mContext.registerReceiverAsUser(new BroadcastReceiver() {
372 @Override
373 public void onReceive(Context context, Intent intent) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800374 synchronized (mLock) {
375 String action = intent.getAction();
376 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
377 onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
378 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
379 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
380 onUserProfilesChangedLocked();
381 }
Victoria Lease38389b62012-09-30 11:44:22 -0700382 }
383 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800384 }, UserHandle.ALL, intentFilter, null, mHandler);
385
386 // switching the user from null to system here performs the bulk of the initialization work.
387 // the user being changed will cause a reload of all user specific settings, which causes
388 // provider initialization, and propagates changes until a steady state is reached
389 mCurrentUserId = UserHandle.USER_NULL;
390 onUserChangedLocked(UserHandle.USER_SYSTEM);
391
392 // initialize in-memory settings values
393 onBackgroundThrottleWhitelistChangedLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700394 }
395
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800396 @GuardedBy("mLock")
397 private void onAppOpChangedLocked() {
398 for (Receiver receiver : mReceivers.values()) {
399 receiver.updateMonitoring(true);
400 }
401 for (LocationProvider p : mProviders) {
402 applyRequirementsLocked(p);
403 }
404 }
405
406 @GuardedBy("mLock")
407 private void onPermissionsChangedLocked() {
408 for (LocationProvider p : mProviders) {
409 applyRequirementsLocked(p);
410 }
411 }
412
413 @GuardedBy("mLock")
414 private void onLocationModeChangedLocked(boolean broadcast) {
415 for (LocationProvider p : mProviders) {
416 p.onLocationModeChangedLocked();
417 }
418
419 if (broadcast) {
420 mContext.sendBroadcastAsUser(
421 new Intent(LocationManager.MODE_CHANGED_ACTION),
422 UserHandle.ALL);
423 }
424 }
425
426 @GuardedBy("mLock")
427 private void onProviderAllowedChangedLocked(boolean broadcast) {
428 for (LocationProvider p : mProviders) {
429 p.onAllowedChangedLocked();
430 }
431
432 if (broadcast) {
433 mContext.sendBroadcastAsUser(
434 new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
435 UserHandle.ALL);
436 }
437 }
438
439 @GuardedBy("mLock")
440 private void onPackageDisappearedLocked(String packageName) {
441 ArrayList<Receiver> deadReceivers = null;
442
443 for (Receiver receiver : mReceivers.values()) {
444 if (receiver.mIdentity.mPackageName.equals(packageName)) {
445 if (deadReceivers == null) {
446 deadReceivers = new ArrayList<>();
447 }
448 deadReceivers.add(receiver);
449 }
450 }
451
452 // perform removal outside of mReceivers loop
453 if (deadReceivers != null) {
454 for (Receiver receiver : deadReceivers) {
455 removeUpdatesLocked(receiver);
456 }
457 }
458 }
459
460 @GuardedBy("mLock")
461 private void onUidImportanceChangedLocked(int uid, int importance) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700462 boolean foreground = isImportanceForeground(importance);
463 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800464 for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
465 String provider = entry.getKey();
466 for (UpdateRecord record : entry.getValue()) {
467 if (record.mReceiver.mIdentity.mUid == uid
468 && record.mIsForegroundUid != foreground) {
gomo48f1a642017-11-10 20:35:46 -0800469 if (D) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800470 Log.d(TAG, "request from uid " + uid + " is now "
gomo48f1a642017-11-10 20:35:46 -0800471 + (foreground ? "foreground" : "background)"));
472 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800473 record.updateForeground(foreground);
474
475 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
476 affectedProviders.add(provider);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700477 }
478 }
479 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800480 }
481 for (String provider : affectedProviders) {
482 applyRequirementsLocked(provider);
483 }
Anil Admal75b9fd62018-11-28 11:22:50 -0800484
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800485 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
486 Identity callerIdentity = entry.getValue();
487 if (callerIdentity.mUid == uid) {
488 if (D) {
489 Log.d(TAG, "gnss measurements listener from uid " + uid
490 + " is now " + (foreground ? "foreground" : "background)"));
491 }
492 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
493 mGnssMeasurementsProvider.addListener(
494 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
495 callerIdentity.mUid, callerIdentity.mPackageName);
496 } else {
497 mGnssMeasurementsProvider.removeListener(
498 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
499 }
500 }
501 }
502
503 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
504 Identity callerIdentity = entry.getValue();
505 if (callerIdentity.mUid == uid) {
506 if (D) {
507 Log.d(TAG, "gnss navigation message listener from uid "
508 + uid + " is now "
509 + (foreground ? "foreground" : "background)"));
510 }
511 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
512 mGnssNavigationMessageProvider.addListener(
513 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
514 callerIdentity.mUid, callerIdentity.mPackageName);
515 } else {
516 mGnssNavigationMessageProvider.removeListener(
517 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
518 }
519 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700520 }
521 }
522
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800523 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700524 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800525 }
526
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800527 @GuardedBy("mLock")
528 private void onBackgroundThrottleIntervalChangedLocked() {
529 for (LocationProvider provider : mProviders) {
530 applyRequirementsLocked(provider);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000531 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800532 }
533
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800534 @GuardedBy("mLock")
535 private void onBackgroundThrottleWhitelistChangedLocked() {
536 String setting = Settings.Global.getString(
537 mContext.getContentResolver(),
538 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
539 if (setting == null) {
540 setting = "";
541 }
542
543 mBackgroundThrottlePackageWhitelist.clear();
544 mBackgroundThrottlePackageWhitelist.addAll(
545 SystemConfig.getInstance().getAllowUnthrottledLocation());
546 mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(",")));
547
548 for (LocationProvider p : mProviders) {
549 applyRequirementsLocked(p);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000550 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800551 }
552
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800553 @GuardedBy("mLock")
554 private void onUserProfilesChangedLocked() {
555 mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(mCurrentUserId);
556 }
557
558 @GuardedBy("mLock")
559 private boolean isCurrentProfileLocked(int userId) {
560 return ArrayUtils.contains(mCurrentUserProfiles, userId);
561 }
562
563 @GuardedBy("mLock")
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700564 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500565 PackageManager pm = mContext.getPackageManager();
566 String systemPackageName = mContext.getPackageName();
567 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
568
569 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
570 new Intent(FUSED_LOCATION_SERVICE_ACTION),
571 PackageManager.GET_META_DATA, mCurrentUserId);
572 for (ResolveInfo rInfo : rInfos) {
573 String packageName = rInfo.serviceInfo.packageName;
574
575 // Check that the signature is in the list of supported sigs. If it's not in
576 // this list the standard provider binding logic won't bind to it.
577 try {
578 PackageInfo pInfo;
579 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
580 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
581 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
582 ", but has wrong signature, ignoring");
583 continue;
584 }
585 } catch (NameNotFoundException e) {
586 Log.e(TAG, "missing package: " + packageName);
587 continue;
588 }
589
590 // Get the version info
591 if (rInfo.serviceInfo.metaData == null) {
592 Log.w(TAG, "Found fused provider without metadata: " + packageName);
593 continue;
594 }
595
596 int version = rInfo.serviceInfo.metaData.getInt(
597 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
598 if (version == 0) {
599 // This should be the fallback fused location provider.
600
601 // Make sure it's in the system partition.
602 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
603 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
604 continue;
605 }
606
607 // Check that the fallback is signed the same as the OS
608 // as a proxy for coreApp="true"
609 if (pm.checkSignatures(systemPackageName, packageName)
610 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800611 if (D) {
612 Log.d(TAG, "Fallback candidate not signed the same as system: "
613 + packageName);
614 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500615 continue;
616 }
617
618 // Found a valid fallback.
619 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
620 return;
621 } else {
622 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
623 }
624 }
625
626 throw new IllegalStateException("Unable to find a fused location provider that is in the "
627 + "system partition with version 0 and signed with the platform certificate. "
628 + "Such a package is needed to provide a default fused location provider in the "
629 + "event that no other fused location provider has been installed or is currently "
630 + "available. For example, coreOnly boot mode when decrypting the data "
631 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
632 }
633
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800634 @GuardedBy("mLock")
635 private void initializeProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700636 // create a passive location provider, which is always enabled
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800637 LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000638 addProviderLocked(passiveProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800639 mPassiveProvider = new PassiveProvider(passiveProviderManager);
640 passiveProviderManager.attachLocked(mPassiveProvider);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700641
Lifu Tang30f95a72016-01-07 23:20:38 -0800642 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700643 // Create a gps location provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800644 LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
645 mRealProviders.add(gnssProviderManager);
646 addProviderLocked(gnssProviderManager);
647
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700648 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
649 gnssProviderManager,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800650 mHandler.getLooper());
651 gnssProviderManager.attachLocked(gnssProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700652
Lifu Tang9363b942016-02-16 18:07:00 -0800653 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800654 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700655 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800656 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
657 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
Lifu Tang818aa2c2016-02-01 01:52:00 -0800658 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
659 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800660 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 }
662
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700663 /*
664 Load package name(s) containing location provider support.
665 These packages can contain services implementing location providers:
666 Geocoder Provider, Network Location Provider, and
667 Fused Location Provider. They will each be searched for
668 service components implementing these providers.
669 The location framework also has support for installation
670 of new location providers at run-time. The new package does not
671 have to be explicitly listed here, however it must have a signature
672 that matches the signature of at least one package on this list.
673 */
674 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500675 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700676 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800677 if (D) {
678 Log.d(TAG, "certificates for location providers pulled from: " +
679 Arrays.toString(pkgs));
680 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500681
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700682 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700683
684 // bind to network provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800685 LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER, true);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700686 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
687 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700688 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700689 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700690 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
691 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700692 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700693 if (networkProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800694 mRealProviders.add(networkProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000695 addProviderLocked(networkProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800696 networkProviderManager.attachLocked(networkProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700697 } else {
gomo48f1a642017-11-10 20:35:46 -0800698 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700699 }
700
701 // bind to fused provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800702 LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700703 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700704 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700705 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700706 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700707 com.android.internal.R.bool.config_enableFusedLocationOverlay,
708 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700709 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700710 if (fusedProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800711 mRealProviders.add(fusedProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000712 addProviderLocked(fusedProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800713 fusedProviderManager.attachLocked(fusedProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700714 } else {
715 Slog.e(TAG, "no fused location provider found",
716 new IllegalStateException("Location service needs a fused location provider"));
717 }
718
719 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700720 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
721 com.android.internal.R.bool.config_enableGeocoderOverlay,
722 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700723 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700724 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800725 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700726 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700727
destradaaf9a274c2014-07-25 15:11:56 -0700728 // bind to geofence provider
729 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800730 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700731 com.android.internal.R.string.config_geofenceProviderPackageName,
732 com.android.internal.R.array.config_locationProviderPackageNames,
Wei Liu5241a4c2015-05-11 14:00:36 -0700733 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900734 null);
destradaaf9a274c2014-07-25 15:11:56 -0700735 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800736 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700737 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900738
Brian Duddiecfa5b5b2019-01-22 18:01:40 +0000739 // bind to hardware activity recognition
740 boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported();
741 ActivityRecognitionHardware activityRecognitionHardware = null;
742 if (activityRecognitionHardwareIsSupported) {
743 activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext);
744 } else {
745 Slog.d(TAG, "Hardware Activity-Recognition not supported.");
746 }
747 ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind(
748 mContext,
749 activityRecognitionHardwareIsSupported,
750 activityRecognitionHardware,
751 com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay,
752 com.android.internal.R.string.config_activityRecognitionHardwarePackageName,
753 com.android.internal.R.array.config_locationProviderPackageNames);
754 if (proxy == null) {
755 Slog.d(TAG, "Unable to bind ActivityRecognitionProxy.");
756 }
757
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900758 String[] testProviderStrings = resources.getStringArray(
759 com.android.internal.R.array.config_testLocationProviders);
760 for (String testProviderString : testProviderStrings) {
761 String fragments[] = testProviderString.split(",");
762 String name = fragments[0].trim();
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900763 ProviderProperties properties = new ProviderProperties(
764 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
765 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
766 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
767 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
768 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
769 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
770 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
771 Integer.parseInt(fragments[8]) /* powerRequirement */,
772 Integer.parseInt(fragments[9]) /* accuracy */);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800773 LocationProvider testProviderManager = new LocationProvider(name);
774 addProviderLocked(testProviderManager);
775 new MockProvider(testProviderManager, properties);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900776 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700777 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700778
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800779 @GuardedBy("mLock")
780 private void onUserChangedLocked(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800781 if (mCurrentUserId == userId) {
782 return;
783 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800784
785 // this call has the side effect of forcing a write to the LOCATION_MODE setting in an OS
786 // upgrade case, and ensures that if anyone checks the LOCATION_MODE setting directly, they
787 // will see it in an appropriate state (at least after that user becomes foreground for the
788 // first time...)
789 isLocationEnabledForUser(userId);
790
791 // let providers know the current user is on the way out before changing the user
792 for (LocationProvider p : mProviders) {
793 p.onUserChangingLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000794 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800795
796 mCurrentUserId = userId;
797 onUserProfilesChangedLocked();
798
799 mBlacklist.switchUser(userId);
800
801 // if the user changes, per-user settings may also have changed
802 onLocationModeChangedLocked(false);
803 onProviderAllowedChangedLocked(false);
Victoria Lease38389b62012-09-30 11:44:22 -0700804 }
805
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800806 private static final class Identity {
807 final int mUid;
808 final int mPid;
809 final String mPackageName;
810
811 Identity(int uid, int pid, String packageName) {
812 mUid = uid;
813 mPid = pid;
814 mPackageName = packageName;
815 }
816 }
817
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700818 private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
819
820 private final String mName;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700821
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800822 // whether this provider should respect LOCATION_PROVIDERS_ALLOWED (ie gps and network)
823 private final boolean mIsManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700824
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800825 // remember to clear binder identity before invoking any provider operation
826 @GuardedBy("mLock")
827 @Nullable protected AbstractLocationProvider mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700828
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800829 @GuardedBy("mLock")
830 private boolean mUseable; // combined state
831 @GuardedBy("mLock")
832 private boolean mAllowed; // state of LOCATION_PROVIDERS_ALLOWED
833 @GuardedBy("mLock")
834 private boolean mEnabled; // state of provider
835
836 @GuardedBy("mLock")
837 @Nullable private ProviderProperties mProperties;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700838
839 private LocationProvider(String name) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800840 this(name, false);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700841 }
842
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800843 private LocationProvider(String name, boolean isManagedBySettings) {
844 mName = name;
845 mIsManagedBySettings = isManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700846
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800847 mProvider = null;
848 mUseable = false;
849 mAllowed = !mIsManagedBySettings;
850 mEnabled = false;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700851 mProperties = null;
852 }
853
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800854 @GuardedBy("mLock")
855 public void attachLocked(AbstractLocationProvider provider) {
856 checkNotNull(provider);
857 checkState(mProvider == null);
858 mProvider = provider;
859
860 onUseableChangedLocked();
861 }
862
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700863 public String getName() {
864 return mName;
865 }
866
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800867 @GuardedBy("mLock")
868 @Nullable
869 public String getPackageLocked() {
870 if (mProvider == null) {
871 return null;
872 } else if (mProvider instanceof LocationProviderProxy) {
873 // safe to not clear binder context since this doesn't call into the actual provider
874 return ((LocationProviderProxy) mProvider).getConnectedPackageName();
875 } else {
876 return mContext.getPackageName();
877 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700878 }
879
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800880 public boolean isMock() {
881 return false;
882 }
883
884 @GuardedBy("mLock")
885 public boolean isPassiveLocked() {
886 return mProvider == mPassiveProvider;
887 }
888
889 @GuardedBy("mLock")
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700890 @Nullable
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800891 public ProviderProperties getPropertiesLocked() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700892 return mProperties;
893 }
894
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800895 @GuardedBy("mLock")
896 public void setRequestLocked(ProviderRequest request, WorkSource workSource) {
897 if (mProvider != null) {
898 long identity = Binder.clearCallingIdentity();
899 try {
900 mProvider.setRequest(request, workSource);
901 } finally {
902 Binder.restoreCallingIdentity(identity);
903 }
904 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700905 }
906
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800907 @GuardedBy("mLock")
908 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700909 pw.println(mName + " provider:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800910 if (isMock()) {
911 pw.println(" mock=true");
912 }
913 pw.println(" attached=" + (mProvider != null));
914 if (mIsManagedBySettings) {
915 pw.println(" allowed=" + mAllowed);
916 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700917 pw.println(" enabled=" + mEnabled);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800918 pw.println(" useable=" + mUseable);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700919 pw.println(" properties=" + mProperties);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800920
921 if (mProvider != null) {
922 long identity = Binder.clearCallingIdentity();
923 try {
924 mProvider.dump(fd, pw, args);
925 } finally {
926 Binder.restoreCallingIdentity(identity);
927 }
928 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700929 }
930
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800931 @GuardedBy("mLock")
932 public long getStatusUpdateTimeLocked() {
933 if (mProvider != null) {
934 long identity = Binder.clearCallingIdentity();
935 try {
936 return mProvider.getStatusUpdateTime();
937 } finally {
938 Binder.restoreCallingIdentity(identity);
939 }
940 } else {
941 return 0;
942 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700943 }
944
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800945 @GuardedBy("mLock")
946 public int getStatusLocked(Bundle extras) {
947 if (mProvider != null) {
948 long identity = Binder.clearCallingIdentity();
949 try {
950 return mProvider.getStatus(extras);
951 } finally {
952 Binder.restoreCallingIdentity(identity);
953 }
954 } else {
955 return AVAILABLE;
956 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700957 }
958
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800959 @GuardedBy("mLock")
960 public void sendExtraCommandLocked(String command, Bundle extras) {
961 if (mProvider != null) {
962 long identity = Binder.clearCallingIdentity();
963 try {
964 mProvider.sendExtraCommand(command, extras);
965 } finally {
966 Binder.restoreCallingIdentity(identity);
967 }
968 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700969 }
970
971 // called from any thread
972 @Override
973 public void onReportLocation(Location location) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800974 // no security check necessary because this is coming from an internal-only interface
975 // move calls coming from below LMS onto a different thread to avoid deadlock
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -0800976 mHandler.post(() -> {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800977 synchronized (mLock) {
978 handleLocationChangedLocked(location, this);
979 }
980 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700981 }
982
983 // called from any thread
984 @Override
985 public void onReportLocation(List<Location> locations) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800986 // move calls coming from below LMS onto a different thread to avoid deadlock
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -0800987 mHandler.post(() -> {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800988 synchronized (mLock) {
989 LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
990 if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
991 Slog.w(TAG, "reportLocationBatch() called without user permission");
992 return;
993 }
994
995 if (mGnssBatchingCallback == null) {
996 Slog.e(TAG, "reportLocationBatch() called without active Callback");
997 return;
998 }
999
1000 try {
1001 mGnssBatchingCallback.onLocationBatch(locations);
1002 } catch (RemoteException e) {
1003 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
1004 }
1005 }
1006 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001007 }
1008
1009 // called from any thread
1010 @Override
1011 public void onSetEnabled(boolean enabled) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001012 // move calls coming from below LMS onto a different thread to avoid deadlock
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001013 mHandler.post(() -> {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001014 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001015 if (enabled == mEnabled) {
1016 return;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001017 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001018
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001019 mEnabled = enabled;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001020
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001021 // update provider allowed settings to reflect enabled status
1022 if (mIsManagedBySettings) {
1023 if (mEnabled && !mAllowed) {
1024 Settings.Secure.putStringForUser(
1025 mContext.getContentResolver(),
1026 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1027 "+" + mName,
1028 mCurrentUserId);
1029 } else if (!mEnabled && mAllowed) {
1030 Settings.Secure.putStringForUser(
1031 mContext.getContentResolver(),
1032 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1033 "-" + mName,
1034 mCurrentUserId);
1035 }
1036 }
1037
1038 onUseableChangedLocked();
1039 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001040 });
1041 }
1042
1043 @Override
1044 public void onSetProperties(ProviderProperties properties) {
Soonil Nagarkar66c0bac2019-01-15 13:36:44 -08001045 // because this does not invoke any other methods which might result in calling back
1046 // into the location provider, it is safe to run this on the calling thread. it is also
1047 // currently necessary to run this on the calling thread to ensure that property changes
1048 // are publicly visibly immediately, ie for mock providers which are created.
1049 synchronized (mLock) {
1050 mProperties = properties;
1051 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001052 }
1053
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001054 @GuardedBy("mLock")
1055 public void onLocationModeChangedLocked() {
1056 onUseableChangedLocked();
1057 }
1058
1059 private boolean isAllowed() {
1060 return isAllowedForUser(mCurrentUserId);
1061 }
1062
1063 private boolean isAllowedForUser(int userId) {
1064 String allowedProviders = Settings.Secure.getStringForUser(
1065 mContext.getContentResolver(),
1066 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1067 userId);
1068 return TextUtils.delimitedStringContains(allowedProviders, ',', mName);
1069 }
1070
1071 @GuardedBy("mLock")
1072 public void onAllowedChangedLocked() {
1073 if (mIsManagedBySettings) {
1074 boolean allowed = isAllowed();
1075 if (allowed == mAllowed) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001076 return;
1077 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001078 mAllowed = allowed;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001079
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001080 // make a best effort to keep the setting matching the real enabled state of the
1081 // provider so that legacy applications aren't broken.
1082 if (mAllowed && !mEnabled) {
1083 Settings.Secure.putStringForUser(
1084 mContext.getContentResolver(),
1085 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1086 "-" + mName,
1087 mCurrentUserId);
1088 }
1089
1090 onUseableChangedLocked();
1091 }
1092 }
1093
1094 @GuardedBy("mLock")
1095 public boolean isUseableLocked() {
1096 return isUseableForUserLocked(mCurrentUserId);
1097 }
1098
1099 @GuardedBy("mLock")
1100 public boolean isUseableForUserLocked(int userId) {
1101 return userId == mCurrentUserId && mUseable;
1102 }
1103
1104 @GuardedBy("mLock")
1105 public void onUseableChangedLocked() {
1106 // if any property that contributes to "useability" here changes state, it MUST result
1107 // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
1108 // guarantee that it will always eventually reach the correct state.
1109 boolean useable = mProvider != null
1110 && mProviders.contains(this) && isLocationEnabled() && mAllowed && mEnabled;
1111 if (useable == mUseable) {
1112 return;
1113 }
1114 mUseable = useable;
1115
1116 if (!mUseable) {
1117 // If any provider has been disabled, clear all last locations for all
1118 // providers. This is to be on the safe side in case a provider has location
1119 // derived from this disabled provider.
1120 mLastLocation.clear();
1121 mLastLocationCoarseInterval.clear();
1122 }
1123
1124 updateProviderUseableLocked(this);
1125 }
1126
1127 @GuardedBy("mLock")
1128 public void onUserChangingLocked() {
1129 // when the user is about to change, we set this provider to un-useable, and notify all
1130 // of the current user clients. when the user is finished changing, useability will be
1131 // updated back via onLocationModeChanged() and onAllowedChanged().
1132 mUseable = false;
1133 updateProviderUseableLocked(this);
1134 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001135 }
1136
1137 private class MockLocationProvider extends LocationProvider {
1138
1139 private MockLocationProvider(String name) {
1140 super(name);
1141 }
1142
1143 @Override
1144 public void attachLocked(AbstractLocationProvider provider) {
1145 checkState(provider instanceof MockProvider);
1146 super.attachLocked(provider);
1147 }
1148
1149 public boolean isMock() {
1150 return true;
1151 }
1152
1153 @GuardedBy("mLock")
1154 public void setEnabledLocked(boolean enabled) {
1155 if (mProvider != null) {
1156 long identity = Binder.clearCallingIdentity();
1157 try {
1158 ((MockProvider) mProvider).setEnabled(enabled);
1159 } finally {
1160 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00001161 }
1162 }
1163 }
1164
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001165 @GuardedBy("mLock")
1166 public void setLocationLocked(Location location) {
1167 if (mProvider != null) {
1168 long identity = Binder.clearCallingIdentity();
1169 try {
1170 ((MockProvider) mProvider).setLocation(location);
1171 } finally {
1172 Binder.restoreCallingIdentity(identity);
1173 }
1174 }
1175 }
1176
1177 @GuardedBy("mLock")
1178 public void setStatusLocked(int status, Bundle extras, long updateTime) {
1179 if (mProvider != null) {
1180 long identity = Binder.clearCallingIdentity();
1181 try {
1182 ((MockProvider) mProvider).setStatus(status, extras, updateTime);
1183 } finally {
1184 Binder.restoreCallingIdentity(identity);
1185 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001186 }
1187 }
1188 }
1189
Victoria Lease38389b62012-09-30 11:44:22 -07001190 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
1192 * location updates.
1193 */
Mike Lockwood48f17512009-04-23 09:12:08 -07001194 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -07001195 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001196 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001197 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001198
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001199 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -07001201 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001202 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
1203 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001204
gomo48f1a642017-11-10 20:35:46 -08001205 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -07001206
David Christie0b837452013-07-29 16:02:13 -07001207 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001208 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -07001209 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001210 private boolean mOpHighPowerMonitoring;
1211 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -07001212 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001214 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001215 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001218 if (listener != null) {
1219 mKey = listener.asBinder();
1220 } else {
1221 mKey = intent;
1222 }
Victoria Lease37425c32012-10-16 16:08:48 -07001223 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001224 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +00001225 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -07001226 workSource = null;
1227 }
1228 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -07001229 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -07001230
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001231 updateMonitoring(true);
1232
Victoria Lease0aa28602013-05-29 15:28:26 -07001233 // construct/configure wakelock
1234 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -07001235 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001236 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001237 }
1238 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -07001239
1240 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
1241 // only need to release it once.
1242 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 }
1244
1245 @Override
1246 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001247 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 }
1249
1250 @Override
1251 public int hashCode() {
1252 return mKey.hashCode();
1253 }
Mike Lockwood3681f262009-05-12 10:52:03 -04001254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 @Override
1256 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001257 StringBuilder s = new StringBuilder();
1258 s.append("Reciever[");
1259 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001261 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001263 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001265 for (String p : mUpdateRecords.keySet()) {
1266 s.append(" ").append(mUpdateRecords.get(p).toString());
1267 }
Wei Wangdd070f22018-06-21 11:29:40 -07001268 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001269 s.append("]");
1270 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271 }
1272
David Christie15b31912013-08-13 15:54:32 -07001273 /**
1274 * Update AppOp monitoring for this receiver.
1275 *
1276 * @param allow If true receiver is currently active, if false it's been removed.
1277 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001278 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001279 if (mHideFromAppOps) {
1280 return;
1281 }
1282
David Christie15b31912013-08-13 15:54:32 -07001283 boolean requestingLocation = false;
1284 boolean requestingHighPowerLocation = false;
1285 if (allow) {
1286 // See if receiver has any enabled update records. Also note if any update records
1287 // are high power (has a high power provider with an interval under a threshold).
1288 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001289 LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001290 if (provider == null) {
1291 continue;
1292 }
1293 if (!provider.isUseableLocked()
1294 && !updateRecord.mRealRequest.isLocationSettingsIgnored()) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001295 continue;
1296 }
1297
1298 requestingLocation = true;
1299 ProviderProperties properties = provider.getPropertiesLocked();
1300 if (properties != null
1301 && properties.mPowerRequirement == Criteria.POWER_HIGH
1302 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1303 requestingHighPowerLocation = true;
1304 break;
David Christie15b31912013-08-13 15:54:32 -07001305 }
1306 }
1307 }
1308
David Christie0b837452013-07-29 16:02:13 -07001309 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001310 mOpMonitoring = updateMonitoring(
1311 requestingLocation,
1312 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001313 AppOpsManager.OP_MONITOR_LOCATION);
1314
1315 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001316 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001317 mOpHighPowerMonitoring = updateMonitoring(
1318 requestingHighPowerLocation,
1319 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001320 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001321 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001322 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001323 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1324 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1325 }
David Christie0b837452013-07-29 16:02:13 -07001326 }
1327
1328 /**
1329 * Update AppOps monitoring for a single location request and op type.
1330 *
gomo48f1a642017-11-10 20:35:46 -08001331 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001332 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001333 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001334 * @return True if monitoring is on for this request/op after updating.
1335 */
1336 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1337 int op) {
1338 if (!currentlyMonitoring) {
1339 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001340 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001341 == AppOpsManager.MODE_ALLOWED;
1342 }
1343 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001344 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001345 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001346 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001347 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001348 return false;
1349 }
1350 }
1351
1352 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001353 }
1354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 public boolean isListener() {
1356 return mListener != null;
1357 }
1358
1359 public boolean isPendingIntent() {
1360 return mPendingIntent != null;
1361 }
1362
1363 public ILocationListener getListener() {
1364 if (mListener != null) {
1365 return mListener;
1366 }
1367 throw new IllegalStateException("Request for non-existent listener");
1368 }
1369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001370 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1371 if (mListener != null) {
1372 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001373 synchronized (this) {
1374 // synchronize to ensure incrementPendingBroadcastsLocked()
1375 // is called before decrementPendingBroadcasts()
1376 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001377 // call this after broadcasting so we do not increment
1378 // if we throw an exeption.
1379 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001380 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 } catch (RemoteException e) {
1382 return false;
1383 }
1384 } else {
1385 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001386 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1388 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001389 synchronized (this) {
1390 // synchronize to ensure incrementPendingBroadcastsLocked()
1391 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001392 mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001393 getResolutionPermission(mAllowedResolutionLevel),
1394 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001395 // call this after broadcasting so we do not increment
1396 // if we throw an exeption.
1397 incrementPendingBroadcastsLocked();
1398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 } catch (PendingIntent.CanceledException e) {
1400 return false;
1401 }
1402 }
1403 return true;
1404 }
1405
1406 public boolean callLocationChangedLocked(Location location) {
1407 if (mListener != null) {
1408 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001409 synchronized (this) {
1410 // synchronize to ensure incrementPendingBroadcastsLocked()
1411 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001412 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001413 // call this after broadcasting so we do not increment
1414 // if we throw an exeption.
1415 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001416 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 } catch (RemoteException e) {
1418 return false;
1419 }
1420 } else {
1421 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001422 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1423 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001425 synchronized (this) {
1426 // synchronize to ensure incrementPendingBroadcastsLocked()
1427 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001428 mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001429 getResolutionPermission(mAllowedResolutionLevel),
1430 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001431 // call this after broadcasting so we do not increment
1432 // if we throw an exeption.
1433 incrementPendingBroadcastsLocked();
1434 }
1435 } catch (PendingIntent.CanceledException e) {
1436 return false;
1437 }
1438 }
1439 return true;
1440 }
1441
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001442 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001443 // First update AppOp monitoring.
1444 // An app may get/lose location access as providers are enabled/disabled.
1445 updateMonitoring(true);
1446
Mike Lockwood48f17512009-04-23 09:12:08 -07001447 if (mListener != null) {
1448 try {
1449 synchronized (this) {
1450 // synchronize to ensure incrementPendingBroadcastsLocked()
1451 // is called before decrementPendingBroadcasts()
1452 if (enabled) {
1453 mListener.onProviderEnabled(provider);
1454 } else {
1455 mListener.onProviderDisabled(provider);
1456 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001457 // call this after broadcasting so we do not increment
1458 // if we throw an exeption.
1459 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001460 }
1461 } catch (RemoteException e) {
1462 return false;
1463 }
1464 } else {
1465 Intent providerIntent = new Intent();
1466 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1467 try {
1468 synchronized (this) {
1469 // synchronize to ensure incrementPendingBroadcastsLocked()
1470 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001471 mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001472 getResolutionPermission(mAllowedResolutionLevel),
1473 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001474 // call this after broadcasting so we do not increment
1475 // if we throw an exeption.
1476 incrementPendingBroadcastsLocked();
1477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 } catch (PendingIntent.CanceledException e) {
1479 return false;
1480 }
1481 }
1482 return true;
1483 }
1484
Nick Pellyf1be6862012-05-15 10:53:42 -07001485 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001487 if (D) Log.d(TAG, "Location listener died");
1488
Soonil Nagarkar68257742019-01-09 19:42:34 +00001489 synchronized (mLock) {
1490 removeUpdatesLocked(this);
1491 }
1492 synchronized (this) {
1493 clearPendingBroadcastsLocked();
1494 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001495 }
1496
Nick Pellye0fd6932012-07-11 10:26:13 -07001497 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001498 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1499 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001500 synchronized (this) {
1501 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001502 }
1503 }
1504
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001505 // this must be called while synchronized by caller in a synchronized block
1506 // containing the sending of the broadcaset
1507 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001508 mPendingBroadcasts++;
1509 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001510 }
1511
1512 private void decrementPendingBroadcastsLocked() {
1513 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001514 if (mWakeLock.isHeld()) {
1515 mWakeLock.release();
1516 }
1517 }
1518 }
1519
1520 public void clearPendingBroadcastsLocked() {
1521 if (mPendingBroadcasts > 0) {
1522 mPendingBroadcasts = 0;
1523 if (mWakeLock.isHeld()) {
1524 mWakeLock.release();
1525 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001526 }
1527 }
1528 }
1529
Nick Pellye0fd6932012-07-11 10:26:13 -07001530 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001531 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001532 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001533 //the receiver list if it is not found. If it is not found then the
1534 //LocationListener was removed when it had a pending broadcast and should
1535 //not be added back.
Soonil Nagarkar68257742019-01-09 19:42:34 +00001536 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001537 IBinder binder = listener.asBinder();
1538 Receiver receiver = mReceivers.get(binder);
1539 if (receiver != null) {
1540 synchronized (receiver) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001541 // so wakelock calls will succeed
1542 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001543 try {
1544 receiver.decrementPendingBroadcastsLocked();
1545 } finally {
1546 Binder.restoreCallingIdentity(identity);
1547 }
David Christie2ff96af2014-01-30 16:09:37 -08001548 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001549 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001550 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 }
1552
Lifu Tang82f893d2016-01-21 18:15:33 -08001553 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001554 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001555 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001556 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001557 } else {
1558 return 0;
1559 }
1560 }
1561
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001562 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001563 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001564 public String getGnssHardwareModelName() {
1565 if (mGnssSystemInfoProvider != null) {
1566 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1567 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001568 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001569 }
1570 }
1571
Wyatt Rileycf879db2017-01-12 13:57:38 -08001572 private boolean hasGnssPermissions(String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001573 synchronized (mLock) {
1574 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1575 checkResolutionLevelIsSufficientForProviderUseLocked(
1576 allowedResolutionLevel,
1577 GPS_PROVIDER);
Wyatt Rileycf879db2017-01-12 13:57:38 -08001578
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001579 int pid = Binder.getCallingPid();
1580 int uid = Binder.getCallingUid();
1581 long identity = Binder.clearCallingIdentity();
1582 try {
1583 return checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1584 } finally {
1585 Binder.restoreCallingIdentity(identity);
1586 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001587 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001588 }
1589
Wyatt Rileycf879db2017-01-12 13:57:38 -08001590 @Override
1591 public int getGnssBatchSize(String packageName) {
1592 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1593 "Location Hardware permission not granted to access hardware batching");
1594
1595 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001596 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001597 } else {
1598 return 0;
1599 }
1600 }
1601
Wyatt Rileycf879db2017-01-12 13:57:38 -08001602 @Override
1603 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1604 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1605 "Location Hardware permission not granted to access hardware batching");
1606
1607 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1608 return false;
1609 }
1610
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001611 synchronized (mLock) {
1612 mGnssBatchingCallback = callback;
1613 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1614 try {
1615 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1616 } catch (RemoteException e) {
1617 // if the remote process registering the listener is already dead, just swallow the
1618 // exception and return
1619 Log.e(TAG, "Remote listener already died.", e);
1620 return false;
1621 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001622
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001623 return true;
1624 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001625 }
1626
1627 private class LinkedCallback implements IBinder.DeathRecipient {
1628 private final IBatchedLocationCallback mCallback;
1629
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001630 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001631 mCallback = callback;
1632 }
1633
1634 @NonNull
1635 public IBatchedLocationCallback getUnderlyingListener() {
1636 return mCallback;
1637 }
1638
1639 @Override
1640 public void binderDied() {
1641 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1642 stopGnssBatch();
1643 removeGnssBatchingCallback();
1644 }
1645 }
1646
Wyatt Rileycf879db2017-01-12 13:57:38 -08001647 @Override
1648 public void removeGnssBatchingCallback() {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001649 synchronized (mLock) {
1650 try {
1651 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1652 0 /* flags */);
1653 } catch (NoSuchElementException e) {
1654 // if the death callback isn't connected (it should be...), log error, swallow the
1655 // exception and return
1656 Log.e(TAG, "Couldn't unlink death callback.", e);
1657 }
1658 mGnssBatchingCallback = null;
1659 mGnssBatchingDeathCallback = null;
Wyatt Rileycf879db2017-01-12 13:57:38 -08001660 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001661 }
1662
Wyatt Rileycf879db2017-01-12 13:57:38 -08001663 @Override
1664 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1665 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1666 "Location Hardware permission not granted to access hardware batching");
1667
1668 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1669 return false;
1670 }
1671
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001672 synchronized (mLock) {
1673 if (mGnssBatchingInProgress) {
1674 // Current design does not expect multiple starts to be called repeatedly
1675 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1676 // Try to clean up anyway, and continue
1677 stopGnssBatch();
1678 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001679
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001680 mGnssBatchingInProgress = true;
1681 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1682 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001683 }
1684
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001685
Wyatt Rileycf879db2017-01-12 13:57:38 -08001686 @Override
1687 public void flushGnssBatch(String packageName) {
1688 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1689 "Location Hardware permission not granted to access hardware batching");
1690
1691 if (!hasGnssPermissions(packageName)) {
1692 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1693 return;
1694 }
1695
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001696 synchronized (mLock) {
1697 if (!mGnssBatchingInProgress) {
1698 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1699 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001700
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001701 if (mGnssBatchingProvider != null) {
1702 mGnssBatchingProvider.flush();
1703 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001704 }
1705 }
1706
Wyatt Rileycf879db2017-01-12 13:57:38 -08001707 @Override
1708 public boolean stopGnssBatch() {
1709 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1710 "Location Hardware permission not granted to access hardware batching");
1711
Soonil Nagarkar68257742019-01-09 19:42:34 +00001712 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001713 if (mGnssBatchingProvider != null) {
1714 mGnssBatchingInProgress = false;
1715 return mGnssBatchingProvider.stop();
1716 } else {
1717 return false;
1718 }
1719 }
1720 }
1721
1722 @GuardedBy("mLock")
1723 private void addProviderLocked(LocationProvider provider) {
1724 Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
1725
1726 mProviders.add(provider);
1727
1728 provider.onAllowedChangedLocked(); // allowed state may change while provider was inactive
1729 provider.onUseableChangedLocked();
1730 }
1731
1732 @GuardedBy("mLock")
1733 private void removeProviderLocked(LocationProvider provider) {
1734 if (mProviders.remove(provider)) {
1735 long identity = Binder.clearCallingIdentity();
1736 try {
1737 provider.onUseableChangedLocked();
1738 } finally {
1739 Binder.restoreCallingIdentity(identity);
1740 }
1741 }
1742 }
1743
1744 @GuardedBy("mLock")
1745 @Nullable
1746 private LocationProvider getLocationProviderLocked(String providerName) {
1747 for (LocationProvider provider : mProviders) {
1748 if (providerName.equals(provider.getName())) {
1749 return provider;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001750 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001751 }
1752
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001753 return null;
Maggie2a9409e2018-03-21 11:47:28 -07001754 }
1755
Victoria Lease37425c32012-10-16 16:08:48 -07001756 private String getResolutionPermission(int resolutionLevel) {
1757 switch (resolutionLevel) {
1758 case RESOLUTION_LEVEL_FINE:
1759 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1760 case RESOLUTION_LEVEL_COARSE:
1761 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1762 default:
1763 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001765 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001766
Victoria Lease37425c32012-10-16 16:08:48 -07001767 private int getAllowedResolutionLevel(int pid, int uid) {
1768 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001769 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001770 return RESOLUTION_LEVEL_FINE;
1771 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001772 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001773 return RESOLUTION_LEVEL_COARSE;
1774 } else {
1775 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001776 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001777 }
1778
Victoria Lease37425c32012-10-16 16:08:48 -07001779 private int getCallerAllowedResolutionLevel() {
1780 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1781 }
1782
Victoria Lease37425c32012-10-16 16:08:48 -07001783 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1784 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001785 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 }
1788
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001789 @GuardedBy("mLock")
1790 private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
1791 if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001792 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001793 return RESOLUTION_LEVEL_FINE;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001794 } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001795 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001796 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001797 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001798 for (LocationProvider lp : mProviders) {
1799 if (!lp.getName().equals(provider)) {
1800 continue;
1801 }
1802
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001803 ProviderProperties properties = lp.getPropertiesLocked();
Laurent Tu941221c2012-10-04 14:21:52 -07001804 if (properties != null) {
1805 if (properties.mRequiresSatellite) {
1806 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001807 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001808 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1809 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001810 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001811 }
1812 }
1813 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001814 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001815
Victoria Lease37425c32012-10-16 16:08:48 -07001816 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001817 }
1818
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001819 @GuardedBy("mLock")
1820 private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001821 String providerName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001822 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
Victoria Lease37425c32012-10-16 16:08:48 -07001823 if (allowedResolutionLevel < requiredResolutionLevel) {
1824 switch (requiredResolutionLevel) {
1825 case RESOLUTION_LEVEL_FINE:
1826 throw new SecurityException("\"" + providerName + "\" location provider " +
1827 "requires ACCESS_FINE_LOCATION permission.");
1828 case RESOLUTION_LEVEL_COARSE:
1829 throw new SecurityException("\"" + providerName + "\" location provider " +
1830 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1831 default:
1832 throw new SecurityException("Insufficient permission for \"" + providerName +
1833 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001834 }
1835 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001836 }
1837
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001838 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001839 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1840 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001841 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001842 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001843 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001844 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001845 }
1846 return -1;
1847 }
1848
Wei Wangb86334f2018-07-03 16:33:24 -07001849 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001850 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001851 case RESOLUTION_LEVEL_COARSE:
1852 return AppOpsManager.OPSTR_COARSE_LOCATION;
1853 case RESOLUTION_LEVEL_FINE:
1854 return AppOpsManager.OPSTR_FINE_LOCATION;
1855 case RESOLUTION_LEVEL_NONE:
1856 // The client is not allowed to get any location, so both FINE and COARSE ops will
1857 // be denied. Pick the most restrictive one to be safe.
1858 return AppOpsManager.OPSTR_FINE_LOCATION;
1859 default:
1860 // Use the most restrictive ops if not sure.
1861 return AppOpsManager.OPSTR_FINE_LOCATION;
1862 }
1863 }
1864
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001865 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001866 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001867 int op = resolutionLevelToOp(allowedResolutionLevel);
1868 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001869 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1870 return false;
1871 }
1872 }
David Christieb870dbf2015-06-22 12:42:53 -07001873
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001874 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001875 }
1876
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001877 private boolean checkLocationAccess(int pid, int uid, String packageName,
1878 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001879 int op = resolutionLevelToOp(allowedResolutionLevel);
1880 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001881 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001882 return false;
1883 }
1884 }
David Christieb870dbf2015-06-22 12:42:53 -07001885
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001886 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001887 }
1888
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001889 /**
Maggie91e630c2018-01-24 17:31:46 -08001890 * Returns all providers by name, including passive and the ones that are not permitted to
1891 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001892 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001893 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 public List<String> getAllProviders() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001895 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001896 ArrayList<String> providers = new ArrayList<>(mProviders.size());
Soonil Nagarkar68257742019-01-09 19:42:34 +00001897 for (LocationProvider provider : mProviders) {
1898 String name = provider.getName();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001899 if (FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001900 continue;
1901 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001902 providers.add(name);
Maggie91e630c2018-01-24 17:31:46 -08001903 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001904 return providers;
Maggie91e630c2018-01-24 17:31:46 -08001905 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 }
1907
Mike Lockwood03ca2162010-04-01 08:10:09 -07001908 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001909 * Return all providers by name, that match criteria and are optionally
1910 * enabled.
1911 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001912 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001913 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001914 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001915 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001916 synchronized (mLock) {
1917 ArrayList<String> providers = new ArrayList<>(mProviders.size());
1918 for (LocationProvider provider : mProviders) {
1919 String name = provider.getName();
1920 if (FUSED_PROVIDER.equals(name)) {
1921 continue;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001922 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001923 if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
1924 continue;
1925 }
1926 if (enabledOnly && !provider.isUseableLocked()) {
1927 continue;
1928 }
1929 if (criteria != null
1930 && !android.location.LocationProvider.propertiesMeetCriteria(
1931 name, provider.getPropertiesLocked(), criteria)) {
1932 continue;
1933 }
1934 providers.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001935 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001936 return providers;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001937 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001938 }
1939
1940 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001941 * Return the name of the best provider given a Criteria object.
1942 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001943 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001944 * has been deprecated as well. So this method now uses
1945 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001946 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001947 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001948 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001949 List<String> providers = getProviders(criteria, enabledOnly);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001950 if (providers.isEmpty()) {
1951 providers = getProviders(null, enabledOnly);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001952 }
1953
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001954 if (!providers.isEmpty()) {
1955 if (providers.contains(GPS_PROVIDER)) {
1956 return GPS_PROVIDER;
1957 } else if (providers.contains(NETWORK_PROVIDER)) {
1958 return NETWORK_PROVIDER;
1959 } else {
1960 return providers.get(0);
1961 }
1962 }
1963
Mike Lockwood03ca2162010-04-01 08:10:09 -07001964 return null;
1965 }
1966
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001967 @GuardedBy("mLock")
1968 private void updateProviderUseableLocked(LocationProvider provider) {
1969 boolean useable = provider.isUseableLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001972
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001973 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001975 for (UpdateRecord record : records) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001976 if (!isCurrentProfileLocked(
1977 UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
1978 continue;
1979 }
1980
1981 // requests that ignore location settings will never provider notifications
1982 if (record.mRealRequest.isLocationSettingsIgnored()) {
1983 continue;
1984 }
1985
1986 // Sends a notification message to the receiver
1987 if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
1988 if (deadReceivers == null) {
1989 deadReceivers = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001991 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 }
1994 }
1995
1996 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001997 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001998 removeUpdatesLocked(deadReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 }
2000 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002001
Soonil Nagarkar68257742019-01-09 19:42:34 +00002002 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002003 }
2004
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002005 @GuardedBy("mLock")
2006 private void applyRequirementsLocked(String providerName) {
2007 LocationProvider provider = getLocationProviderLocked(providerName);
2008 if (provider != null) {
2009 applyRequirementsLocked(provider);
2010 }
2011 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002012
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002013 @GuardedBy("mLock")
2014 private void applyRequirementsLocked(LocationProvider provider) {
2015 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002016 WorkSource worksource = new WorkSource();
2017 ProviderRequest providerRequest = new ProviderRequest();
2018
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002019 long backgroundThrottleInterval;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002020
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002021 long identity = Binder.clearCallingIdentity();
2022 try {
2023 backgroundThrottleInterval = Settings.Global.getLong(
2024 mContext.getContentResolver(),
2025 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
2026 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
2027 } finally {
2028 Binder.restoreCallingIdentity(identity);
2029 }
2030
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002031 if (records != null && !records.isEmpty()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002032 // initialize the low power mode to true and set to false if any of the records requires
2033 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002034 for (UpdateRecord record : records) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002035 if (!isCurrentProfileLocked(
2036 UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
2037 continue;
2038 }
2039 if (!checkLocationAccess(
2040 record.mReceiver.mIdentity.mPid,
2041 record.mReceiver.mIdentity.mUid,
2042 record.mReceiver.mIdentity.mPackageName,
2043 record.mReceiver.mAllowedResolutionLevel)) {
2044 continue;
2045 }
2046 if (!provider.isUseableLocked()
2047 && !record.mRealRequest.isLocationSettingsIgnored()) {
2048 continue;
2049 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002050
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002051 LocationRequest locationRequest = record.mRealRequest;
2052 long interval = locationRequest.getInterval();
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002053
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002054 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
2055 if (!record.mIsForegroundUid) {
2056 interval = Math.max(interval, backgroundThrottleInterval);
Victoria Leaseb711d572012-10-02 13:14:11 -07002057 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002058 if (interval != locationRequest.getInterval()) {
2059 locationRequest = new LocationRequest(locationRequest);
2060 locationRequest.setInterval(interval);
2061 }
2062 }
2063
2064 record.mRequest = locationRequest;
2065 providerRequest.locationRequests.add(locationRequest);
2066 if (!locationRequest.isLowPowerMode()) {
2067 providerRequest.lowPowerMode = false;
2068 }
2069 if (interval < providerRequest.interval) {
2070 providerRequest.reportLocation = true;
2071 providerRequest.interval = interval;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002072 }
2073 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002074
2075 if (providerRequest.reportLocation) {
2076 // calculate who to blame for power
2077 // This is somewhat arbitrary. We pick a threshold interval
2078 // that is slightly higher that the minimum interval, and
2079 // spread the blame across all applications with a request
2080 // under that threshold.
2081 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
2082 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002083 if (isCurrentProfileLocked(
2084 UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002085 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07002086
2087 // Don't assign battery blame for update records whose
2088 // client has no permission to receive location data.
2089 if (!providerRequest.locationRequests.contains(locationRequest)) {
2090 continue;
2091 }
2092
Victoria Leaseb711d572012-10-02 13:14:11 -07002093 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07002094 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00002095 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07002096 worksource.add(record.mReceiver.mWorkSource);
2097 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00002098 // Assign blame to caller if there's no WorkSource associated with
2099 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07002100 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002101 record.mReceiver.mIdentity.mUid,
2102 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07002103 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002104 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002105 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 }
2108 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002109
2110 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002111 provider.setRequestLocked(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002112 }
2113
Narayan Kamath32684dd2018-01-08 17:32:51 +00002114 /**
2115 * Whether a given {@code WorkSource} associated with a Location request is valid.
2116 */
2117 private static boolean isValidWorkSource(WorkSource workSource) {
2118 if (workSource.size() > 0) {
2119 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
2120 // by tags.
2121 return workSource.getName(0) != null;
2122 } else {
2123 // For now, make sure callers have supplied an attribution tag for use with
2124 // AppOpsManager. This might be relaxed in the future.
2125 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
2126 return workChains != null && !workChains.isEmpty() &&
2127 workChains.get(0).getAttributionTag() != null;
2128 }
2129 }
2130
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002131 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002132 public String[] getBackgroundThrottlingWhitelist() {
2133 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002134 return mBackgroundThrottlePackageWhitelist.toArray(new String[0]);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002135 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002136 }
2137
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002138 @GuardedBy("mLock")
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002139 private boolean isThrottlingExemptLocked(Identity identity) {
2140 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002141 return true;
2142 }
2143
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002144 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002145 return true;
2146 }
2147
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002148 for (LocationProvider provider : mProviders) {
2149 if (identity.mPackageName.equals(provider.getPackageLocked())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002150 return true;
2151 }
2152 }
2153
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002154 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002155 }
2156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002157 private class UpdateRecord {
2158 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002159 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002160 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002161 private final Receiver mReceiver;
2162 private boolean mIsForegroundUid;
2163 private Location mLastFixBroadcast;
2164 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002165
2166 /**
2167 * Note: must be constructed with lock held.
2168 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002169 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002171 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002172 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002173 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002174 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002175 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002176
2177 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2178 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002179 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002180 mRecordsByProvider.put(provider, records);
2181 }
2182 if (!records.contains(this)) {
2183 records.add(this);
2184 }
David Christie2ff96af2014-01-30 16:09:37 -08002185
2186 // Update statistics for historical location requests by package/provider
2187 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002188 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2189 mIsForegroundUid);
2190 }
2191
2192 /**
2193 * Method to be called when record changes foreground/background
2194 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002195 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002196 mIsForegroundUid = isForeground;
2197 mRequestStatistics.updateForeground(
2198 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199 }
2200
2201 /**
David Christie2ff96af2014-01-30 16:09:37 -08002202 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002204 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002205 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002206
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002207 // remove from mRecordsByProvider
2208 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2209 if (globalRecords != null) {
2210 globalRecords.remove(this);
2211 }
2212
2213 if (!removeReceiver) return; // the caller will handle the rest
2214
2215 // remove from Receiver#mUpdateRecords
2216 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002217 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002218
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002219 // and also remove the Receiver if it has no more update records
2220 if (receiverRecords.size() == 0) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002221 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002223 }
2224
2225 @Override
2226 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002227 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002228 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2229 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002230 + ")" + " " + mRealRequest + " "
2231 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002233 }
2234
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002235 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002236 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002237 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002238 IBinder binder = listener.asBinder();
2239 Receiver receiver = mReceivers.get(binder);
2240 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002241 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2242 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002243 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002244 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002245 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002246 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002247 return null;
2248 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002249 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002250 }
2251 return receiver;
2252 }
2253
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002254 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002255 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002256 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002257 Receiver receiver = mReceivers.get(intent);
2258 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002259 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2260 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002261 mReceivers.put(intent, receiver);
2262 }
2263 return receiver;
2264 }
2265
Victoria Lease37425c32012-10-16 16:08:48 -07002266 /**
2267 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2268 * and consistency requirements.
2269 *
2270 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002271 * @return a version of request that meets the given resolution and consistency requirements
2272 * @hide
2273 */
gomo48f1a642017-11-10 20:35:46 -08002274 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2275 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002276 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002277 if (!callerHasLocationHardwarePermission) {
2278 // allow setting low power mode only for callers with location hardware permission
2279 sanitizedRequest.setLowPowerMode(false);
2280 }
Victoria Lease37425c32012-10-16 16:08:48 -07002281 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2282 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002283 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002284 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002285 break;
2286 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002287 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002288 break;
2289 }
2290 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002291 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2292 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002293 }
Victoria Lease37425c32012-10-16 16:08:48 -07002294 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2295 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002296 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002297 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002298 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002299 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002300 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002301 }
Victoria Lease37425c32012-10-16 16:08:48 -07002302 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002303 }
2304
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002305 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002306 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002307 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002308 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002309 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002310 String[] packages = mPackageManager.getPackagesForUid(uid);
2311 if (packages == null) {
2312 throw new SecurityException("invalid UID " + uid);
2313 }
2314 for (String pkg : packages) {
2315 if (packageName.equals(pkg)) return;
2316 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002317 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002318 }
2319
Nick Pellye0fd6932012-07-11 10:26:13 -07002320 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002321 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002322 PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002323 synchronized (mLock) {
2324 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2325 checkPackageName(packageName);
2326 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2327 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2328 request.getProvider());
2329 WorkSource workSource = request.getWorkSource();
2330 if (workSource != null && !workSource.isEmpty()) {
2331 mContext.enforceCallingOrSelfPermission(
2332 Manifest.permission.UPDATE_DEVICE_STATS, null);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002333 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002334 boolean hideFromAppOps = request.getHideFromAppOps();
2335 if (hideFromAppOps) {
2336 mContext.enforceCallingOrSelfPermission(
2337 Manifest.permission.UPDATE_APP_OPS_STATS, null);
2338 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002339 if (request.isLocationSettingsIgnored()) {
2340 mContext.enforceCallingOrSelfPermission(
2341 Manifest.permission.WRITE_SECURE_SETTINGS, null);
2342 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002343 boolean callerHasLocationHardwarePermission =
2344 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2345 == PERMISSION_GRANTED;
2346 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2347 allowedResolutionLevel,
2348 callerHasLocationHardwarePermission);
2349
2350 final int pid = Binder.getCallingPid();
2351 final int uid = Binder.getCallingUid();
2352
2353 long identity = Binder.clearCallingIdentity();
2354 try {
2355
2356 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2357 // a location.
2358 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
2359
2360 if (intent == null && listener == null) {
2361 throw new IllegalArgumentException("need either listener or intent");
2362 } else if (intent != null && listener != null) {
2363 throw new IllegalArgumentException(
2364 "cannot register both listener and intent");
2365 }
2366
2367 Receiver receiver;
2368 if (intent != null) {
2369 receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
2370 hideFromAppOps);
2371 } else {
2372 receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
2373 hideFromAppOps);
2374 }
2375 requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
2376 } finally {
2377 Binder.restoreCallingIdentity(identity);
2378 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002379 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002380 }
2381
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002382 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002383 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002384 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002385 // Figure out the provider. Either its explicitly request (legacy use cases), or
2386 // use the fused provider
2387 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2388 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002389 if (name == null) {
2390 throw new IllegalArgumentException("provider name must not be null");
2391 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002392
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002393 LocationProvider provider = getLocationProviderLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002394 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002395 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002396 }
2397
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002398 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002399 if (D) {
2400 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2401 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2402 + (record.mIsForegroundUid ? "foreground" : "background")
2403 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002404 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002405 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002406
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002407 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2408 if (oldRecord != null) {
2409 oldRecord.disposeLocked(false);
2410 }
2411
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002412 if (!provider.isUseableLocked() && !request.isLocationSettingsIgnored()) {
2413 // Notify the listener that updates are currently disabled - but only if the request
2414 // does not ignore location settings
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002415 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002416 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002417
2418 applyRequirementsLocked(name);
2419
David Christie0b837452013-07-29 16:02:13 -07002420 // Update the monitoring here just in case multiple location requests were added to the
2421 // same receiver (this request may be high power and the initial might not have been).
2422 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002423 }
2424
Nick Pellye0fd6932012-07-11 10:26:13 -07002425 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002426 public void removeUpdates(ILocationListener listener, PendingIntent intent,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002427 String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002428 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002429
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002430 int pid = Binder.getCallingPid();
2431 int uid = Binder.getCallingUid();
2432
2433 if (intent == null && listener == null) {
2434 throw new IllegalArgumentException("need either listener or intent");
2435 } else if (intent != null && listener != null) {
2436 throw new IllegalArgumentException("cannot register both listener and intent");
2437 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002438
Soonil Nagarkar68257742019-01-09 19:42:34 +00002439 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002440 Receiver receiver;
2441 if (intent != null) {
2442 receiver = getReceiverLocked(intent, pid, uid, packageName, null, false);
2443 } else {
2444 receiver = getReceiverLocked(listener, pid, uid, packageName, null, false);
2445 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002446
Soonil Nagarkar68257742019-01-09 19:42:34 +00002447 long identity = Binder.clearCallingIdentity();
2448 try {
2449 removeUpdatesLocked(receiver);
2450 } finally {
2451 Binder.restoreCallingIdentity(identity);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002452 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002454 }
2455
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002456 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002457 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002458 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002459
2460 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2461 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2462 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002463 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002465 }
2466
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002467 receiver.updateMonitoring(false);
2468
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002469 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002470 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002471 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2472 if (oldRecords != null) {
2473 // Call dispose() on the obsolete update records.
2474 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002475 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002476 record.disposeLocked(false);
2477 }
2478 // Accumulate providers
2479 providers.addAll(oldRecords.keySet());
2480 }
2481
2482 // update provider
2483 for (String provider : providers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002484 applyRequirementsLocked(provider);
2485 }
2486 }
2487
Nick Pellye0fd6932012-07-11 10:26:13 -07002488 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002489 public Location getLastLocation(LocationRequest r, String packageName) {
2490 if (D) Log.d(TAG, "getLastLocation: " + r);
2491 synchronized (mLock) {
2492 LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
2493 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2494 checkPackageName(packageName);
2495 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2496 request.getProvider());
2497 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002498
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002499 final int pid = Binder.getCallingPid();
2500 final int uid = Binder.getCallingUid();
2501 final long identity = Binder.clearCallingIdentity();
2502 try {
2503 if (mBlacklist.isBlacklisted(packageName)) {
2504 if (D) {
2505 Log.d(TAG, "not returning last loc for blacklisted app: "
2506 + packageName);
2507 }
2508 return null;
gomo48f1a642017-11-10 20:35:46 -08002509 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002510
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002511 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
2512 if (D) {
2513 Log.d(TAG, "not returning last loc for no op app: "
2514 + packageName);
2515 }
2516 return null;
gomo48f1a642017-11-10 20:35:46 -08002517 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002518
Soonil Nagarkar68257742019-01-09 19:42:34 +00002519 // Figure out the provider. Either its explicitly request (deprecated API's),
2520 // or use the fused provider
2521 String name = request.getProvider();
2522 if (name == null) name = LocationManager.FUSED_PROVIDER;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002523 LocationProvider provider = getLocationProviderLocked(name);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002524 if (provider == null) return null;
2525
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002526 // only the current user or location providers may get location this way
2527 if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isLocationProviderLocked(
2528 uid)) {
2529 return null;
2530 }
2531
2532 if (!provider.isUseableLocked()) {
2533 return null;
2534 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002535
2536 Location location;
2537 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2538 // Make sure that an app with coarse permissions can't get frequent location
2539 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2540 location = mLastLocationCoarseInterval.get(name);
2541 } else {
2542 location = mLastLocation.get(name);
2543 }
2544 if (location == null) {
2545 return null;
2546 }
2547
2548 // Don't return stale location to apps with foreground-only location permission.
2549 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002550 long locationAgeMs = SystemClock.elapsedRealtime()
2551 - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2552 if ((locationAgeMs > Settings.Global.getLong(
2553 mContext.getContentResolver(),
2554 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2555 DEFAULT_LAST_LOCATION_MAX_AGE_MS))
Soonil Nagarkar68257742019-01-09 19:42:34 +00002556 && (mAppOps.unsafeCheckOp(op, uid, packageName)
2557 == AppOpsManager.MODE_FOREGROUND)) {
2558 return null;
2559 }
2560
2561 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2562 Location noGPSLocation = location.getExtraLocation(
2563 Location.EXTRA_NO_GPS_LOCATION);
2564 if (noGPSLocation != null) {
2565 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
2566 }
2567 } else {
2568 return new Location(location);
2569 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002570 return null;
2571 } finally {
2572 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002573 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002574 }
2575 }
2576
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002577 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002578 public boolean injectLocation(Location location) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002579 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2580 "Location Hardware permission not granted to inject location");
2581 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2582 "Access Fine Location permission not granted to inject Location");
2583
2584 if (location == null) {
2585 if (D) {
2586 Log.d(TAG, "injectLocation(): called with null location");
2587 }
2588 return false;
2589 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002590
Soonil Nagarkar68257742019-01-09 19:42:34 +00002591 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002592 LocationProvider provider = getLocationProviderLocked(location.getProvider());
2593 if (provider == null || !provider.isUseableLocked()) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002594 return false;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002595 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002596
2597 // NOTE: If last location is already available, location is not injected. If
2598 // provider's normal source (like a GPS chipset) have already provided an output
2599 // there is no need to inject this location.
2600 if (mLastLocation.get(provider.getName()) != null) {
2601 return false;
2602 }
2603
2604 updateLastLocationLocked(location, provider.getName());
2605 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002606 }
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002607 }
2608
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002609 @Override
2610 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2611 String packageName) {
2612 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002613 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2614 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002615 if (intent == null) {
2616 throw new IllegalArgumentException("invalid pending intent: " + null);
Victoria Lease56e675b2012-11-05 19:25:06 -08002617 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002618 checkPackageName(packageName);
2619 synchronized (mLock) {
2620 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2621 request.getProvider());
2622 // Require that caller can manage given document
2623 boolean callerHasLocationHardwarePermission =
2624 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2625 == PERMISSION_GRANTED;
2626 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2627 allowedResolutionLevel,
2628 callerHasLocationHardwarePermission);
2629
2630 if (D) {
2631 Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
2632 }
2633
2634 // geo-fence manager uses the public location API, need to clear identity
2635 int uid = Binder.getCallingUid();
2636 // TODO: http://b/23822629
2637 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
2638 // temporary measure until geofences work for secondary users
2639 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2640 return;
2641 }
2642 long identity = Binder.clearCallingIdentity();
2643 try {
2644 mGeofenceManager.addFence(sanitizedRequest, geofence, intent,
2645 allowedResolutionLevel,
2646 uid, packageName);
2647 } finally {
2648 Binder.restoreCallingIdentity(identity);
2649 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002650 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002651 }
2652
2653 @Override
2654 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002655 if (intent == null) {
2656 throw new IllegalArgumentException("invalid pending intent: " + null);
2657 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002658 checkPackageName(packageName);
2659
2660 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2661
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002662 // geo-fence manager uses the public location API, need to clear identity
2663 long identity = Binder.clearCallingIdentity();
2664 try {
2665 mGeofenceManager.removeFence(geofence, intent);
2666 } finally {
2667 Binder.restoreCallingIdentity(identity);
2668 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002669 }
2670
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002671 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002672 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002673 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002674 return false;
2675 }
2676
Anil Admal75b9fd62018-11-28 11:22:50 -08002677 // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
2678 // measurements listeners.
2679 return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002680 }
2681
Nick Pellye0fd6932012-07-11 10:26:13 -07002682 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002683 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002684 mGnssStatusProvider.removeListener(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
2686
Nick Pellye0fd6932012-07-11 10:26:13 -07002687 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002688 public boolean addGnssMeasurementsListener(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002689 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002690 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002691 return false;
2692 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002693
Soonil Nagarkar68257742019-01-09 19:42:34 +00002694 synchronized (mLock) {
2695 Identity callerIdentity
2696 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002697 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002698 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002699 long identity = Binder.clearCallingIdentity();
2700 try {
2701 if (isThrottlingExemptLocked(callerIdentity)
2702 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002703 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002704 return mGnssMeasurementsProvider.addListener(listener,
2705 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002706 }
2707 } finally {
2708 Binder.restoreCallingIdentity(identity);
2709 }
2710
2711 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002712 }
destradaaea8a8a62014-06-23 18:19:03 -07002713 }
2714
2715 @Override
gomo226b7b72018-12-12 16:49:39 -08002716 public void injectGnssMeasurementCorrections(
2717 GnssMeasurementCorrections measurementCorrections, String packageName) {
2718 mContext.enforceCallingPermission(
2719 android.Manifest.permission.LOCATION_HARDWARE,
2720 "Location Hardware permission not granted to inject GNSS measurement corrections.");
2721 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2722 mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
2723 } else {
2724 Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
2725 }
2726 }
2727
2728 @Override
2729 public int getGnssCapabilities(String packageName) {
2730 mContext.enforceCallingPermission(
2731 android.Manifest.permission.LOCATION_HARDWARE,
2732 "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
2733 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2734 return -1;
2735 }
2736 return mGnssMeasurementsProvider.getGnssCapabilities();
2737 }
2738
2739 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002740 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002741 if (mGnssMeasurementsProvider == null) {
2742 return;
2743 }
2744
Soonil Nagarkar68257742019-01-09 19:42:34 +00002745 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002746 mGnssMeasurementsListeners.remove(listener.asBinder());
2747 mGnssMeasurementsProvider.removeListener(listener);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002748 }
destradaaea8a8a62014-06-23 18:19:03 -07002749 }
2750
2751 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002752 public boolean addGnssNavigationMessageListener(
2753 IGnssNavigationMessageListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002754 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002755 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002756 return false;
2757 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002758
Soonil Nagarkar68257742019-01-09 19:42:34 +00002759 synchronized (mLock) {
2760 Identity callerIdentity
2761 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002762
Anil Admal75b9fd62018-11-28 11:22:50 -08002763 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002764 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002765 long identity = Binder.clearCallingIdentity();
2766 try {
2767 if (isThrottlingExemptLocked(callerIdentity)
2768 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002769 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002770 return mGnssNavigationMessageProvider.addListener(listener,
2771 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002772 }
2773 } finally {
2774 Binder.restoreCallingIdentity(identity);
2775 }
2776
2777 return true;
Wei Liu5241a4c2015-05-11 14:00:36 -07002778 }
destradaa4b3e3932014-07-21 18:01:47 -07002779 }
2780
2781 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002782 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2783 if (mGnssNavigationMessageProvider != null) {
2784 synchronized (mLock) {
2785 mGnssNavigationMessageListeners.remove(listener.asBinder());
2786 mGnssNavigationMessageProvider.removeListener(listener);
2787 }
2788 }
2789 }
2790
2791 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002792 public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
2793 if (providerName == null) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002794 // throw NullPointerException to remain compatible with previous implementation
2795 throw new NullPointerException();
2796 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002797 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002798 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2799 providerName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002800
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002801 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
2802 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
2803 != PERMISSION_GRANTED)) {
2804 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2805 }
2806
2807 LocationProvider provider = getLocationProviderLocked(providerName);
2808 if (provider != null) {
2809 provider.sendExtraCommandLocked(command, extras);
2810 }
2811
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002812 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002814 }
2815
Nick Pellye0fd6932012-07-11 10:26:13 -07002816 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002817 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002818 if (Binder.getCallingUid() != Process.myUid()) {
2819 throw new SecurityException(
2820 "calling sendNiResponse from outside of the system is not allowed");
2821 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002822 try {
2823 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002824 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002825 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002826 return false;
2827 }
2828 }
2829
Nick Pellye0fd6932012-07-11 10:26:13 -07002830 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002831 public ProviderProperties getProviderProperties(String providerName) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002832 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002833 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2834 providerName);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002835
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002836 LocationProvider provider = getLocationProviderLocked(providerName);
2837 if (provider == null) {
2838 return null;
2839 }
2840 return provider.getPropertiesLocked();
2841 }
Jason Monkb71218a2015-06-17 14:44:39 -04002842 }
2843
Wei Wang980b7c22018-12-06 17:53:00 -08002844 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002845 public String getNetworkProviderPackage() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002846 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002847 LocationProvider provider = getLocationProviderLocked(NETWORK_PROVIDER);
2848 if (provider == null) {
2849 return null;
2850 }
2851 return provider.getPackageLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +00002852 }
Maggie2a9409e2018-03-21 11:47:28 -07002853 }
2854
Maggie2a9409e2018-03-21 11:47:28 -07002855 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002856 public void setLocationControllerExtraPackage(String packageName) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002857 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2858 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002859 synchronized (mLock) {
2860 mLocationControllerExtraPackage = packageName;
2861 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002862 }
2863
2864 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002865 public String getLocationControllerExtraPackage() {
2866 synchronized (mLock) {
2867 return mLocationControllerExtraPackage;
2868 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002869 }
2870
2871 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002872 public void setLocationControllerExtraPackageEnabled(boolean enabled) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002873 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2874 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002875 synchronized (mLock) {
2876 mLocationControllerExtraPackageEnabled = enabled;
2877 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002878 }
2879
2880 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002881 public boolean isLocationControllerExtraPackageEnabled() {
2882 synchronized (mLock) {
2883 return mLocationControllerExtraPackageEnabled
2884 && (mLocationControllerExtraPackage != null);
2885 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002886 }
2887
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002888 private boolean isLocationEnabled() {
2889 return isLocationEnabledForUser(mCurrentUserId);
2890 }
2891
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002892 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002893 public boolean isLocationEnabledForUser(int userId) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002894 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002895 if (UserHandle.getCallingUserId() != userId) {
2896 mContext.enforceCallingOrSelfPermission(
2897 Manifest.permission.INTERACT_ACROSS_USERS,
2898 "Requires INTERACT_ACROSS_USERS permission");
2899 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002900
Soonil Nagarkar68257742019-01-09 19:42:34 +00002901 long identity = Binder.clearCallingIdentity();
2902 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002903 boolean enabled;
2904 try {
2905 enabled = Settings.Secure.getIntForUser(
2906 mContext.getContentResolver(),
2907 Settings.Secure.LOCATION_MODE,
2908 userId) != Settings.Secure.LOCATION_MODE_OFF;
2909 } catch (Settings.SettingNotFoundException e) {
2910 // OS upgrade case where mode isn't set yet
2911 enabled = !TextUtils.isEmpty(Settings.Secure.getStringForUser(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002912 mContext.getContentResolver(),
2913 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002914 userId));
2915
2916 try {
2917 Settings.Secure.putIntForUser(
2918 mContext.getContentResolver(),
2919 Settings.Secure.LOCATION_MODE,
2920 enabled
2921 ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
2922 : Settings.Secure.LOCATION_MODE_OFF,
2923 userId);
2924 } catch (RuntimeException ex) {
2925 // any problem with writing should not be propagated
2926 Slog.e(TAG, "error updating location mode", ex);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002927 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002928 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002929 return enabled;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002930 } finally {
2931 Binder.restoreCallingIdentity(identity);
2932 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002933 }
2934
Maggie2a9409e2018-03-21 11:47:28 -07002935 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002936 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002937 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002938 if (UserHandle.getCallingUserId() != userId) {
2939 mContext.enforceCallingOrSelfPermission(
2940 Manifest.permission.INTERACT_ACROSS_USERS,
2941 "Requires INTERACT_ACROSS_USERS permission");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002942 }
2943
Maggie2a9409e2018-03-21 11:47:28 -07002944 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2945 // so we discourage its use
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002946 if (FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002947
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002948 synchronized (mLock) {
2949 LocationProvider provider = getLocationProviderLocked(providerName);
2950 return provider != null && provider.isUseableForUserLocked(userId);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002951 }
Maggie2a9409e2018-03-21 11:47:28 -07002952 }
2953
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002954 @GuardedBy("mLock")
2955 private boolean isLocationProviderLocked(int uid) {
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002956 if (uid == Process.SYSTEM_UID) {
2957 return true;
2958 }
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002959
David Christie1f141c12014-05-14 15:11:15 -07002960 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2961 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002962 return false;
2963 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002964 for (LocationProvider provider : mProviders) {
2965 String packageName = provider.getPackageLocked();
2966 if (packageName == null) {
2967 continue;
2968 }
2969 if (ArrayUtils.contains(packageNames, packageName)) {
David Christie1f141c12014-05-14 15:11:15 -07002970 return true;
2971 }
2972 }
2973 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002974 }
2975
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002976 @GuardedBy("mLock")
2977 private static boolean shouldBroadcastSafeLocked(
Laurent Tu75defb62012-11-01 16:21:52 -07002978 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002979 // Always broadcast the first update
2980 if (lastLoc == null) {
2981 return true;
2982 }
2983
Nick Pellyf1be6862012-05-15 10:53:42 -07002984 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002985 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002986 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2987 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002988 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002989 return false;
2990 }
2991
2992 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002993 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002994 if (minDistance > 0.0) {
2995 if (loc.distanceTo(lastLoc) <= minDistance) {
2996 return false;
2997 }
2998 }
2999
Laurent Tu75defb62012-11-01 16:21:52 -07003000 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003001 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07003002 return false;
3003 }
3004
3005 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003006 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003007 }
3008
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003009 @GuardedBy("mLock")
3010 private void handleLocationChangedLocked(Location location, LocationProvider provider) {
3011 if (!mProviders.contains(provider)) {
3012 return;
3013 }
3014 if (!location.isComplete()) {
3015 Log.w(TAG, "Dropping incomplete location: " + location);
3016 return;
3017 }
3018
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003019 // only notify passive provider and update last location for locations that come from
3020 // useable providers
3021 if (provider.isUseableLocked()) {
3022 if (!provider.isPassiveLocked()) {
3023 mPassiveProvider.updateLocation(location);
3024 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003025 }
3026
Soonil Nagarkar68257742019-01-09 19:42:34 +00003027 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003028 long now = SystemClock.elapsedRealtime();
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003029 if (provider.isUseableLocked()) {
3030 updateLastLocationLocked(location, provider.getName());
Mike Lockwood4e50b782009-04-03 08:24:43 -07003031 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003032
David Christie1b9b7b12013-04-15 15:31:11 -07003033 // Update last known coarse interval location if enough time has passed.
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003034 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(
3035 provider.getName());
David Christie1b9b7b12013-04-15 15:31:11 -07003036 if (lastLocationCoarseInterval == null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003037 lastLocationCoarseInterval = new Location(location);
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003038
3039 if (provider.isUseableLocked()) {
3040 mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
3041 }
David Christie1b9b7b12013-04-15 15:31:11 -07003042 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003043 long timeDiffNanos = location.getElapsedRealtimeNanos()
David Christie1b9b7b12013-04-15 15:31:11 -07003044 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
3045 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003046 lastLocationCoarseInterval.set(location);
David Christie1b9b7b12013-04-15 15:31:11 -07003047 }
3048 // Don't ever return a coarse location that is more recent than the allowed update
3049 // interval (i.e. don't allow an app to keep registering and unregistering for
3050 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003051 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07003052 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3053
Laurent Tu60ec50a2012-10-04 17:00:10 -07003054 // Skip if there are no UpdateRecords for this provider.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003055 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Laurent Tu60ec50a2012-10-04 17:00:10 -07003056 if (records == null || records.size() == 0) return;
3057
Victoria Lease09016ab2012-09-16 12:33:15 -07003058 // Fetch coarse location
3059 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07003060 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003061 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
3062 }
3063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003064 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003065 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07003066
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003067 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003068 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003070 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003071
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003072 if (!provider.isUseableLocked() && !r.mRealRequest.isLocationSettingsIgnored()) {
3073 continue;
3074 }
3075
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003076 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003077 if (!isCurrentProfileLocked(receiverUserId)
3078 && !isLocationProviderLocked(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003079 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003080 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003081 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003082 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003083 }
3084 continue;
3085 }
3086
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003087 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003088 if (D) {
3089 Log.d(TAG, "skipping loc update for blacklisted app: " +
3090 receiver.mIdentity.mPackageName);
3091 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003092 continue;
3093 }
3094
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003095 if (!reportLocationAccessNoThrow(
3096 receiver.mIdentity.mPid,
3097 receiver.mIdentity.mUid,
3098 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003099 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003100 if (D) {
3101 Log.d(TAG, "skipping loc update for no op app: " +
3102 receiver.mIdentity.mPackageName);
3103 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003104 continue;
3105 }
3106
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003107 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003108 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3109 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003110 } else {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003111 notifyLocation = location; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003112 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003113 if (notifyLocation != null) {
3114 Location lastLoc = r.mLastFixBroadcast;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003115 if ((lastLoc == null)
3116 || shouldBroadcastSafeLocked(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003117 if (lastLoc == null) {
3118 lastLoc = new Location(notifyLocation);
3119 r.mLastFixBroadcast = lastLoc;
3120 } else {
3121 lastLoc.set(notifyLocation);
3122 }
3123 if (!receiver.callLocationChangedLocked(notifyLocation)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003124 Slog.w(TAG, "RemoteException calling onLocationChanged on "
3125 + receiver);
Victoria Lease09016ab2012-09-16 12:33:15 -07003126 receiverDead = true;
3127 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003128 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003129 }
3130 }
3131
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003132 // TODO: location provider status callbacks have been disabled and deprecated, and are
3133 // guarded behind this setting now. should be removed completely post-Q
3134 if (Settings.Global.getInt(mContext.getContentResolver(),
3135 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003136 long newStatusUpdateTime = provider.getStatusUpdateTimeLocked();
3137 Bundle extras = new Bundle();
3138 int status = provider.getStatusLocked(extras);
3139
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003140 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3141 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003142 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003144 r.mLastStatusBroadcast = newStatusUpdateTime;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003145 if (!receiver.callStatusChangedLocked(provider.getName(), status, extras)) {
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003146 receiverDead = true;
3147 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3148 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003149 }
3150 }
3151
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003152 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003153 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003154 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003155 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003156 }
3157 deadUpdateRecords.add(r);
3158 }
3159 // track dead receivers
3160 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003161 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003162 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003163 }
3164 if (!deadReceivers.contains(receiver)) {
3165 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003166 }
3167 }
3168 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003169
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003170 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003171 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003172 for (Receiver receiver : deadReceivers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003173 removeUpdatesLocked(receiver);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003174 }
3175 }
3176 if (deadUpdateRecords != null) {
3177 for (UpdateRecord r : deadUpdateRecords) {
3178 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003180 applyRequirementsLocked(provider);
Victoria Lease8b38b292012-12-04 15:04:43 -08003181 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182 }
3183
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003184 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00003185 private void updateLastLocationLocked(Location location, String provider) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003186 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3187 Location lastNoGPSLocation;
3188 Location lastLocation = mLastLocation.get(provider);
3189 if (lastLocation == null) {
3190 lastLocation = new Location(provider);
3191 mLastLocation.put(provider, lastLocation);
3192 } else {
3193 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3194 if (noGPSLocation == null && lastNoGPSLocation != null) {
3195 // New location has no no-GPS location: adopt last no-GPS location. This is set
3196 // directly into location because we do not want to notify COARSE clients.
3197 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3198 }
3199 }
3200 lastLocation.set(location);
3201 }
3202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 // Geocoder
3204
Nick Pellye0fd6932012-07-11 10:26:13 -07003205 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003206 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003207 return mGeocodeProvider != null;
3208 }
3209
Nick Pellye0fd6932012-07-11 10:26:13 -07003210 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003211 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003212 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003213 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003214 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3215 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003217 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003218 }
3219
Mike Lockwooda55c3212009-04-15 11:10:11 -04003220
Nick Pellye0fd6932012-07-11 10:26:13 -07003221 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003222 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003223 double lowerLeftLatitude, double lowerLeftLongitude,
3224 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003225 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003226
3227 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003228 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3229 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3230 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003231 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003232 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 }
3234
3235 // Mock Providers
3236
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003237 private boolean canCallerAccessMockLocation(String opPackageName) {
3238 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3239 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 }
3241
Nick Pellye0fd6932012-07-11 10:26:13 -07003242 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003243 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003244 if (!canCallerAccessMockLocation(opPackageName)) {
3245 return;
3246 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003247
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003248 if (PASSIVE_PROVIDER.equals(name)) {
Mike Lockwooda4903f22010-02-17 06:42:23 -05003249 throw new IllegalArgumentException("Cannot mock the passive location provider");
3250 }
3251
Soonil Nagarkar68257742019-01-09 19:42:34 +00003252 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003253 long identity = Binder.clearCallingIdentity();
3254 try {
3255 LocationProvider oldProvider = getLocationProviderLocked(name);
3256 if (oldProvider != null) {
3257 if (oldProvider.isMock()) {
3258 throw new IllegalArgumentException(
3259 "Provider \"" + name + "\" already exists");
3260 }
3261
3262 removeProviderLocked(oldProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003263 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003264
3265 MockLocationProvider mockProviderManager = new MockLocationProvider(name);
3266 addProviderLocked(mockProviderManager);
3267 mockProviderManager.attachLocked(new MockProvider(mockProviderManager, properties));
3268 } finally {
3269 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003270 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003271 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003272 }
3273
Nick Pellye0fd6932012-07-11 10:26:13 -07003274 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003275 public void removeTestProvider(String name, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003276 if (!canCallerAccessMockLocation(opPackageName)) {
3277 return;
3278 }
3279
Soonil Nagarkar68257742019-01-09 19:42:34 +00003280 synchronized (mLock) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003281 long identity = Binder.clearCallingIdentity();
3282 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003283 LocationProvider testProvider = getLocationProviderLocked(name);
3284 if (testProvider == null || !testProvider.isMock()) {
3285 throw new IllegalArgumentException("Provider \"" + name + "\" unknown");
3286 }
3287
3288 removeProviderLocked(testProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003289
Soonil Nagarkar68257742019-01-09 19:42:34 +00003290 // reinstate real provider if available
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003291 LocationProvider realProvider = null;
3292 for (LocationProvider provider : mRealProviders) {
3293 if (name.equals(provider.getName())) {
3294 realProvider = provider;
3295 break;
3296 }
3297 }
3298
Soonil Nagarkar68257742019-01-09 19:42:34 +00003299 if (realProvider != null) {
3300 addProviderLocked(realProvider);
3301 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003302 } finally {
3303 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003304 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003305 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003306 }
3307
Nick Pellye0fd6932012-07-11 10:26:13 -07003308 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003309 public void setTestProviderLocation(String providerName, Location location,
Soonil Nagarkar68257742019-01-09 19:42:34 +00003310 String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003311 if (!canCallerAccessMockLocation(opPackageName)) {
3312 return;
3313 }
3314
Soonil Nagarkar68257742019-01-09 19:42:34 +00003315 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003316 LocationProvider testProvider = getLocationProviderLocked(providerName);
3317 if (testProvider == null || !testProvider.isMock()) {
3318 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003320
3321 String locationProvider = location.getProvider();
3322 if (!TextUtils.isEmpty(locationProvider) && !providerName.equals(locationProvider)) {
3323 // The location has an explicit provider that is different from the mock
3324 // provider name. The caller may be trying to fool us via b/33091107.
3325 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3326 providerName + "!=" + location.getProvider());
3327 }
3328
3329 ((MockLocationProvider) testProvider).setLocationLocked(location);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003330 }
3331 }
3332
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003333 @Override
3334 public void setTestProviderEnabled(String providerName, boolean enabled, String opPackageName) {
3335 if (!canCallerAccessMockLocation(opPackageName)) {
3336 return;
3337 }
3338
3339 synchronized (mLock) {
3340 LocationProvider testProvider = getLocationProviderLocked(providerName);
3341 if (testProvider == null || !testProvider.isMock()) {
3342 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3343 }
3344
3345 ((MockLocationProvider) testProvider).setEnabledLocked(enabled);
3346 }
3347 }
3348
3349 @Override
3350 public void setTestProviderStatus(String providerName, int status, Bundle extras,
3351 long updateTime, String opPackageName) {
3352 if (!canCallerAccessMockLocation(opPackageName)) {
3353 return;
3354 }
3355
3356 synchronized (mLock) {
3357 LocationProvider testProvider = getLocationProviderLocked(providerName);
3358 if (testProvider == null || !testProvider.isMock()) {
3359 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3360 }
3361
3362 ((MockLocationProvider) testProvider).setStatusLocked(status, extras, updateTime);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003363 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003365
3366 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003367 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003368 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003369
Soonil Nagarkar68257742019-01-09 19:42:34 +00003370 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003371 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3372 if (mGnssMetricsProvider != null) {
3373 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3374 }
3375 return;
3376 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 pw.println("Current Location Manager state:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003378 pw.println(" Location Mode: " + isLocationEnabled());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003379 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003380 for (Receiver receiver : mReceivers.values()) {
3381 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003382 }
David Christie2ff96af2014-01-30 16:09:37 -08003383 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003384 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3385 pw.println(" " + entry.getKey() + ":");
3386 for (UpdateRecord record : entry.getValue()) {
3387 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003388 }
3389 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003390 pw.println(" Active GnssMeasurement Listeners:");
3391 for (Identity identity : mGnssMeasurementsListeners.values()) {
3392 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3393 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3394 }
3395 pw.println(" Active GnssNavigationMessage Listeners:");
3396 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3397 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3398 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3399 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003400 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003401 for (LocationProvider provider : mProviders) {
3402 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003403 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003404 + ((LocationProviderProxy) provider.mProvider)
3405 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003406 }
3407 }
David Christie2ff96af2014-01-30 16:09:37 -08003408 pw.println(" Historical Records by Provider:");
3409 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3410 : mRequestStatistics.statistics.entrySet()) {
3411 PackageProviderKey key = entry.getKey();
3412 PackageStatistics stats = entry.getValue();
3413 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3414 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003415 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003416 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3417 String provider = entry.getKey();
3418 Location location = entry.getValue();
3419 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003420 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003421
David Christie1b9b7b12013-04-15 15:31:11 -07003422 pw.println(" Last Known Locations Coarse Intervals:");
3423 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3424 String provider = entry.getKey();
3425 Location location = entry.getValue();
3426 pw.println(" " + provider + ": " + location);
3427 }
3428
Nick Pellye0fd6932012-07-11 10:26:13 -07003429 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003430
Nick Pelly4035f5a2012-08-17 14:43:49 -07003431 pw.append(" ");
3432 mBlacklist.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003433
Wei Wang980b7c22018-12-06 17:53:00 -08003434 if (mLocationControllerExtraPackage != null) {
3435 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
3436 + " enabled: " + mLocationControllerExtraPackageEnabled);
3437 }
3438
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003439 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3440 pw.println(" Throttling Whitelisted Packages:");
3441 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3442 pw.println(" " + packageName);
3443 }
3444 }
3445
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003446 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003447 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003448
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003449 if (args.length > 0 && "short".equals(args[0])) {
3450 return;
3451 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003452 for (LocationProvider provider : mProviders) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003453 provider.dumpLocked(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003454 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003455 if (mGnssBatchingInProgress) {
3456 pw.println(" GNSS batching in progress");
3457 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003458 }
3459 }
3460}