blob: 53f796b289ace4a517a5d227c8fd6a1d28cbec3c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Maggieaa080f92018-01-04 15:35:11 -080019import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080020import static android.location.LocationManager.FUSED_PROVIDER;
21import static android.location.LocationManager.GPS_PROVIDER;
22import static android.location.LocationManager.NETWORK_PROVIDER;
23import static android.location.LocationManager.PASSIVE_PROVIDER;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070024import static android.location.LocationProvider.AVAILABLE;
Soonil Nagarkar94749f72018-11-08 11:46:43 -080025import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS;
Maggieaa080f92018-01-04 15:35:11 -080026
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080027import static com.android.internal.util.Preconditions.checkNotNull;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070028import static com.android.internal.util.Preconditions.checkState;
29
Wei Wang980b7c22018-12-06 17:53:00 -080030import android.Manifest;
Wyatt Rileycf879db2017-01-12 13:57:38 -080031import android.annotation.NonNull;
Wyatt Riley49097c02018-03-15 09:14:43 -070032import android.annotation.Nullable;
Maggieaa080f92018-01-04 15:35:11 -080033import android.app.ActivityManager;
34import android.app.AppOpsManager;
35import android.app.PendingIntent;
36import android.content.BroadcastReceiver;
Maggieaa080f92018-01-04 15:35:11 -080037import android.content.Context;
38import android.content.Intent;
39import android.content.IntentFilter;
40import android.content.pm.ApplicationInfo;
41import android.content.pm.PackageInfo;
42import android.content.pm.PackageManager;
43import android.content.pm.PackageManager.NameNotFoundException;
44import android.content.pm.PackageManagerInternal;
45import android.content.pm.ResolveInfo;
46import android.content.pm.Signature;
47import android.content.res.Resources;
48import android.database.ContentObserver;
Maggieaa080f92018-01-04 15:35:11 -080049import android.location.Address;
50import android.location.Criteria;
51import android.location.GeocoderParams;
52import android.location.Geofence;
gomo226b7b72018-12-12 16:49:39 -080053import android.location.GnssMeasurementCorrections;
Maggieaa080f92018-01-04 15:35:11 -080054import android.location.IBatchedLocationCallback;
55import android.location.IGnssMeasurementsListener;
56import android.location.IGnssNavigationMessageListener;
57import android.location.IGnssStatusListener;
Maggieaa080f92018-01-04 15:35:11 -080058import android.location.IGpsGeofenceHardware;
59import android.location.ILocationListener;
60import android.location.ILocationManager;
61import android.location.INetInitiatedListener;
62import android.location.Location;
63import android.location.LocationManager;
Maggieaa080f92018-01-04 15:35:11 -080064import android.location.LocationRequest;
65import android.os.Binder;
66import android.os.Bundle;
67import android.os.Handler;
68import android.os.IBinder;
Maggieaa080f92018-01-04 15:35:11 -080069import android.os.PowerManager;
70import android.os.Process;
71import android.os.RemoteException;
72import android.os.SystemClock;
73import android.os.UserHandle;
74import android.os.UserManager;
75import android.os.WorkSource;
Narayan Kamath32684dd2018-01-08 17:32:51 +000076import android.os.WorkSource.WorkChain;
Maggieaa080f92018-01-04 15:35:11 -080077import android.provider.Settings;
78import android.text.TextUtils;
Soonil Nagarkar681d7112017-02-23 17:14:16 -080079import android.util.ArrayMap;
Soonil Nagarkar2b565df2017-02-14 13:33:23 -080080import android.util.ArraySet;
Maggieaa080f92018-01-04 15:35:11 -080081import android.util.EventLog;
82import android.util.Log;
83import android.util.Slog;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -070084
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080085import com.android.internal.annotations.GuardedBy;
destradaaea8a8a62014-06-23 18:19:03 -070086import com.android.internal.content.PackageMonitor;
87import com.android.internal.location.ProviderProperties;
88import com.android.internal.location.ProviderRequest;
Fyodor Kupolov7f98aa42016-04-07 14:56:25 -070089import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060090import com.android.internal.util.DumpUtils;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -080091import com.android.internal.util.Preconditions;
Soonil Nagarkar1575a042018-10-24 17:54:54 -070092import com.android.server.location.AbstractLocationProvider;
destradaaea8a8a62014-06-23 18:19:03 -070093import com.android.server.location.GeocoderProxy;
94import com.android.server.location.GeofenceManager;
95import com.android.server.location.GeofenceProxy;
Yu-Han Yang3557cc72018-03-21 12:48:36 -070096import com.android.server.location.GnssBatchingProvider;
Lifu Tang818aa2c2016-02-01 01:52:00 -080097import com.android.server.location.GnssLocationProvider;
98import com.android.server.location.GnssMeasurementsProvider;
99import com.android.server.location.GnssNavigationMessageProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800100import com.android.server.location.GnssStatusListenerHelper;
destradaaea8a8a62014-06-23 18:19:03 -0700101import com.android.server.location.LocationBlacklist;
102import com.android.server.location.LocationFudger;
destradaaea8a8a62014-06-23 18:19:03 -0700103import com.android.server.location.LocationProviderProxy;
104import com.android.server.location.LocationRequestStatistics;
105import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
106import com.android.server.location.LocationRequestStatistics.PackageStatistics;
107import com.android.server.location.MockProvider;
108import com.android.server.location.PassiveProvider;
Yu-Han Yanga4d250e2018-10-02 21:29:20 -0700109
Mike Lockwood43e33f22010-03-26 10:41:48 -0400110import java.io.FileDescriptor;
111import java.io.PrintWriter;
112import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700113import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -0400114import java.util.HashMap;
115import java.util.HashSet;
116import java.util.List;
117import java.util.Map;
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800118import java.util.Map.Entry;
Wyatt Rileycf879db2017-01-12 13:57:38 -0800119import java.util.NoSuchElementException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120
121/**
122 * The service class that manages LocationProviders and issues location
123 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 */
Victoria Lease5cd731a2012-12-19 15:04:21 -0800125public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 private static final String TAG = "LocationManagerService";
JP Abgrallf79811e72013-02-01 18:45:05 -0800127 public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700128
Olivier Gaillard7a222662017-11-20 16:07:24 +0000129 private static final String WAKELOCK_KEY = "*location*";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130
Victoria Lease37425c32012-10-16 16:08:48 -0700131 // Location resolution level: no location data whatsoever
132 private static final int RESOLUTION_LEVEL_NONE = 0;
133 // Location resolution level: coarse location data only
134 private static final int RESOLUTION_LEVEL_COARSE = 1;
135 // Location resolution level: fine location data
136 private static final int RESOLUTION_LEVEL_FINE = 2;
137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700139 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700140
141 private static final String NETWORK_LOCATION_SERVICE_ACTION =
Stan Chesnutt39062dd2013-07-22 14:33:30 -0700142 "com.android.location.service.v3.NetworkLocationProvider";
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700143 private static final String FUSED_LOCATION_SERVICE_ACTION =
144 "com.android.location.service.FusedLocationProvider";
145
David Christie1b9b7b12013-04-15 15:31:11 -0700146 private static final long NANOS_PER_MILLI = 1000000L;
147
David Christie0b837452013-07-29 16:02:13 -0700148 // The maximum interval a location request can have and still be considered "high power".
149 private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
150
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700151 private static final int FOREGROUND_IMPORTANCE_CUTOFF
gomo48f1a642017-11-10 20:35:46 -0800152 = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700153
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800154 // default background throttling interval if not overriden in settings
Soonil Nagarkarde6780a2017-02-07 10:39:41 -0800155 private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800156
Wei Wangdd070f22018-06-21 11:29:40 -0700157 // Default value for maximum age of last location returned to applications with foreground-only
158 // location permissions.
159 private static final long DEFAULT_LAST_LOCATION_MAX_AGE_MS = 20 * 60 * 1000;
160
Nick Pellyf1be6862012-05-15 10:53:42 -0700161 // Location Providers may sometimes deliver location updates
162 // slightly faster that requested - provide grace period so
163 // we don't unnecessarily filter events that are otherwise on
164 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700165 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700166
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700167 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
168
Soonil Nagarkar68257742019-01-09 19:42:34 +0000169 private final Object mLock = new Object();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800170 private final Context mContext;
171 private final Handler mHandler;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800173 private AppOpsManager mAppOps;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174 private PackageManager mPackageManager;
Victoria Lease0aa28602013-05-29 15:28:26 -0700175 private PowerManager mPowerManager;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800176 private ActivityManager mActivityManager;
Amith Yamasanib27528d2014-06-05 15:02:10 -0700177 private UserManager mUserManager;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800178
179 private GeofenceManager mGeofenceManager;
180 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700181 private GeocoderProxy mGeocodeProvider;
Anil Admal75b9fd62018-11-28 11:22:50 -0800182 private GnssStatusListenerHelper mGnssStatusProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700183 private INetInitiatedListener mNetInitiatedListener;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700184 private PassiveProvider mPassiveProvider; // track passive provider for special cases
185 private LocationBlacklist mBlacklist;
Lifu Tang818aa2c2016-02-01 01:52:00 -0800186 private GnssMeasurementsProvider mGnssMeasurementsProvider;
187 private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800188 @GuardedBy("mLock")
Wei Wang980b7c22018-12-06 17:53:00 -0800189 private String mLocationControllerExtraPackage;
190 private boolean mLocationControllerExtraPackageEnabled;
Wei Liu5241a4c2015-05-11 14:00:36 -0700191 private IGpsGeofenceHardware mGpsGeofenceProxy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700192
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800193 // list of currently active providers
194 @GuardedBy("mLock")
195 private final ArrayList<LocationProvider> mProviders = new ArrayList<>();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000196
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800197 // list of non-mock providers, so that when mock providers replace real providers, they can be
198 // later re-replaced
199 @GuardedBy("mLock")
200 private final ArrayList<LocationProvider> mRealProviders = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800202 @GuardedBy("mLock")
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800203 private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700204 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800205 new HashMap<>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700206
David Christie2ff96af2014-01-30 16:09:37 -0800207 private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
208
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700209 // mapping from provider name to last known location
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800210 @GuardedBy("mLock")
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800211 private final HashMap<String, Location> mLastLocation = new HashMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212
David Christie1b9b7b12013-04-15 15:31:11 -0700213 // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
214 // locations stored here are not fudged for coarse permissions.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800215 @GuardedBy("mLock")
David Christie1b9b7b12013-04-15 15:31:11 -0700216 private final HashMap<String, Location> mLastLocationCoarseInterval =
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800217 new HashMap<>();
David Christie1b9b7b12013-04-15 15:31:11 -0700218
Soonil Nagarkar2b565df2017-02-14 13:33:23 -0800219 private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800220
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800221 @GuardedBy("mLock")
Wyatt Riley11cc7492018-01-17 08:48:27 -0800222 private final ArrayMap<IBinder, Identity> mGnssMeasurementsListeners = new ArrayMap<>();
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800223
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800224 @GuardedBy("mLock")
Wyatt Riley11cc7492018-01-17 08:48:27 -0800225 private final ArrayMap<IBinder, Identity>
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800226 mGnssNavigationMessageListeners = new ArrayMap<>();
227
Victoria Lease38389b62012-09-30 11:44:22 -0700228 // current active user on the device - other users are denied location data
Xiaohui Chena4490622015-09-22 15:29:31 -0700229 private int mCurrentUserId = UserHandle.USER_SYSTEM;
gomo48f1a642017-11-10 20:35:46 -0800230 private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
Victoria Lease38389b62012-09-30 11:44:22 -0700231
Lifu Tang9363b942016-02-16 18:07:00 -0800232 private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
Lifu Tang82f893d2016-01-21 18:15:33 -0800233
Siddharth Raybb608c82017-03-16 11:33:34 -0700234 private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
Wyatt Rileyaa420d52017-07-03 15:14:42 -0700235
Yu-Han Yang3557cc72018-03-21 12:48:36 -0700236 private GnssBatchingProvider mGnssBatchingProvider;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800237 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800238 private IBatchedLocationCallback mGnssBatchingCallback;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800239 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800240 private LinkedCallback mGnssBatchingDeathCallback;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800241 @GuardedBy("mLock")
Wyatt Rileycf879db2017-01-12 13:57:38 -0800242 private boolean mGnssBatchingInProgress = false;
243
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700244 public LocationManagerService(Context context) {
245 super();
246 mContext = context;
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -0800247 mHandler = FgThread.getHandler();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800248
Svet Ganovadc1cf42015-06-15 16:36:24 -0700249 // Let the package manager query which are the default location
250 // providers as they get certain permissions granted by default.
251 PackageManagerInternal packageManagerInternal = LocalServices.getService(
252 PackageManagerInternal.class);
253 packageManagerInternal.setLocationPackagesProvider(
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700254 userId -> mContext.getResources().getStringArray(
255 com.android.internal.R.array.config_locationProviderPackageNames));
Wei Wangffb94e62019-01-14 00:05:45 -0800256 packageManagerInternal.setLocationExtraPackagesProvider(
257 userId -> mContext.getResources().getStringArray(
258 com.android.internal.R.array.config_locationExtraPackageNames));
Svet Ganovadc1cf42015-06-15 16:36:24 -0700259
Wyatt Rileya8037ff2016-08-04 16:10:06 -0700260 // most startup is deferred until systemRunning()
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700261 }
262
Svetoslav Ganova0027152013-06-25 14:59:53 -0700263 public void systemRunning() {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000264 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800265 initializeLocked();
Victoria Lease5cd731a2012-12-19 15:04:21 -0800266 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800267 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700268
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800269 @GuardedBy("mLock")
270 private void initializeLocked() {
271 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
272 mPackageManager = mContext.getPackageManager();
273 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
274 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
275 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
276
277 mLocationFudger = new LocationFudger(mContext, mHandler);
278 mBlacklist = new LocationBlacklist(mContext, mHandler);
279 mBlacklist.init();
280 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
281
282 // prepare providers
283 initializeProvidersLocked();
284
285 // add listeners
286 mAppOps.startWatchingMode(
287 AppOpsManager.OP_COARSE_LOCATION,
288 null,
289 AppOpsManager.WATCH_FOREGROUND_CHANGES,
290 new AppOpsManager.OnOpChangedInternalListener() {
291 public void onOpChanged(int op, String packageName) {
292 synchronized (mLock) {
293 onAppOpChangedLocked();
294 }
295 }
296 });
297 mPackageManager.addOnPermissionsChangeListener(
298 uid -> {
299 synchronized (mLock) {
300 onPermissionsChangedLocked();
301 }
302 });
303
304 mActivityManager.addOnUidImportanceListener(
305 (uid, importance) -> {
306 synchronized (mLock) {
307 onUidImportanceChangedLocked(uid, importance);
308 }
309 },
310 FOREGROUND_IMPORTANCE_CUTOFF);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700311 mContext.getContentResolver().registerContentObserver(
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800312 Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), true,
313 new ContentObserver(mHandler) {
Victoria Lease5cd731a2012-12-19 15:04:21 -0800314 @Override
315 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000316 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800317 onLocationModeChangedLocked(true);
318 }
319 }
320 }, UserHandle.USER_ALL);
321 mContext.getContentResolver().registerContentObserver(
322 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
323 new ContentObserver(mHandler) {
324 @Override
325 public void onChange(boolean selfChange) {
326 synchronized (mLock) {
327 onProviderAllowedChangedLocked(true);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000328 }
Victoria Lease5cd731a2012-12-19 15:04:21 -0800329 }
330 }, UserHandle.USER_ALL);
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800331 mContext.getContentResolver().registerContentObserver(
332 Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
333 true,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800334 new ContentObserver(mHandler) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800335 @Override
336 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000337 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800338 onBackgroundThrottleIntervalChangedLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000339 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800340 }
341 }, UserHandle.USER_ALL);
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800342 mContext.getContentResolver().registerContentObserver(
gomo48f1a642017-11-10 20:35:46 -0800343 Settings.Global.getUriFor(
344 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
345 true,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800346 new ContentObserver(mHandler) {
gomo48f1a642017-11-10 20:35:46 -0800347 @Override
348 public void onChange(boolean selfChange) {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000349 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800350 onBackgroundThrottleWhitelistChangedLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000351 }
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -0800352 }
gomo48f1a642017-11-10 20:35:46 -0800353 }, UserHandle.USER_ALL);
Wei Wangdd070f22018-06-21 11:29:40 -0700354
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800355 new PackageMonitor() {
356 @Override
357 public void onPackageDisappeared(String packageName, int reason) {
358 synchronized (mLock) {
359 LocationManagerService.this.onPackageDisappearedLocked(packageName);
360 }
361 }
362 }.register(mContext, mHandler.getLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700363
Victoria Lease38389b62012-09-30 11:44:22 -0700364 IntentFilter intentFilter = new IntentFilter();
365 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Amith Yamasanib27528d2014-06-05 15:02:10 -0700366 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
367 intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
Victoria Lease38389b62012-09-30 11:44:22 -0700368
369 mContext.registerReceiverAsUser(new BroadcastReceiver() {
370 @Override
371 public void onReceive(Context context, Intent intent) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800372 synchronized (mLock) {
373 String action = intent.getAction();
374 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
375 onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
376 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
377 || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
378 onUserProfilesChangedLocked();
379 }
Victoria Lease38389b62012-09-30 11:44:22 -0700380 }
381 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800382 }, UserHandle.ALL, intentFilter, null, mHandler);
383
384 // switching the user from null to system here performs the bulk of the initialization work.
385 // the user being changed will cause a reload of all user specific settings, which causes
386 // provider initialization, and propagates changes until a steady state is reached
387 mCurrentUserId = UserHandle.USER_NULL;
388 onUserChangedLocked(UserHandle.USER_SYSTEM);
389
390 // initialize in-memory settings values
391 onBackgroundThrottleWhitelistChangedLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700392 }
393
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800394 @GuardedBy("mLock")
395 private void onAppOpChangedLocked() {
396 for (Receiver receiver : mReceivers.values()) {
397 receiver.updateMonitoring(true);
398 }
399 for (LocationProvider p : mProviders) {
400 applyRequirementsLocked(p);
401 }
402 }
403
404 @GuardedBy("mLock")
405 private void onPermissionsChangedLocked() {
406 for (LocationProvider p : mProviders) {
407 applyRequirementsLocked(p);
408 }
409 }
410
411 @GuardedBy("mLock")
412 private void onLocationModeChangedLocked(boolean broadcast) {
413 for (LocationProvider p : mProviders) {
414 p.onLocationModeChangedLocked();
415 }
416
417 if (broadcast) {
418 mContext.sendBroadcastAsUser(
419 new Intent(LocationManager.MODE_CHANGED_ACTION),
420 UserHandle.ALL);
421 }
422 }
423
424 @GuardedBy("mLock")
425 private void onProviderAllowedChangedLocked(boolean broadcast) {
426 for (LocationProvider p : mProviders) {
427 p.onAllowedChangedLocked();
428 }
429
430 if (broadcast) {
431 mContext.sendBroadcastAsUser(
432 new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
433 UserHandle.ALL);
434 }
435 }
436
437 @GuardedBy("mLock")
438 private void onPackageDisappearedLocked(String packageName) {
439 ArrayList<Receiver> deadReceivers = null;
440
441 for (Receiver receiver : mReceivers.values()) {
442 if (receiver.mIdentity.mPackageName.equals(packageName)) {
443 if (deadReceivers == null) {
444 deadReceivers = new ArrayList<>();
445 }
446 deadReceivers.add(receiver);
447 }
448 }
449
450 // perform removal outside of mReceivers loop
451 if (deadReceivers != null) {
452 for (Receiver receiver : deadReceivers) {
453 removeUpdatesLocked(receiver);
454 }
455 }
456 }
457
458 @GuardedBy("mLock")
459 private void onUidImportanceChangedLocked(int uid, int importance) {
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700460 boolean foreground = isImportanceForeground(importance);
461 HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800462 for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
463 String provider = entry.getKey();
464 for (UpdateRecord record : entry.getValue()) {
465 if (record.mReceiver.mIdentity.mUid == uid
466 && record.mIsForegroundUid != foreground) {
gomo48f1a642017-11-10 20:35:46 -0800467 if (D) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800468 Log.d(TAG, "request from uid " + uid + " is now "
gomo48f1a642017-11-10 20:35:46 -0800469 + (foreground ? "foreground" : "background)"));
470 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800471 record.updateForeground(foreground);
472
473 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
474 affectedProviders.add(provider);
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700475 }
476 }
477 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800478 }
479 for (String provider : affectedProviders) {
480 applyRequirementsLocked(provider);
481 }
Anil Admal75b9fd62018-11-28 11:22:50 -0800482
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800483 for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
484 Identity callerIdentity = entry.getValue();
485 if (callerIdentity.mUid == uid) {
486 if (D) {
487 Log.d(TAG, "gnss measurements listener from uid " + uid
488 + " is now " + (foreground ? "foreground" : "background)"));
489 }
490 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
491 mGnssMeasurementsProvider.addListener(
492 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
493 callerIdentity.mUid, callerIdentity.mPackageName);
494 } else {
495 mGnssMeasurementsProvider.removeListener(
496 IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
497 }
498 }
499 }
500
501 for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
502 Identity callerIdentity = entry.getValue();
503 if (callerIdentity.mUid == uid) {
504 if (D) {
505 Log.d(TAG, "gnss navigation message listener from uid "
506 + uid + " is now "
507 + (foreground ? "foreground" : "background)"));
508 }
509 if (foreground || isThrottlingExemptLocked(entry.getValue())) {
510 mGnssNavigationMessageProvider.addListener(
511 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
512 callerIdentity.mUid, callerIdentity.mPackageName);
513 } else {
514 mGnssNavigationMessageProvider.removeListener(
515 IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
516 }
517 }
Soonil Nagarkare056b0d2017-06-21 13:08:16 -0700518 }
519 }
520
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800521 private static boolean isImportanceForeground(int importance) {
Soonil Nagarkarebda0282017-04-10 14:55:37 -0700522 return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -0800523 }
524
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800525 @GuardedBy("mLock")
526 private void onBackgroundThrottleIntervalChangedLocked() {
527 for (LocationProvider provider : mProviders) {
528 applyRequirementsLocked(provider);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000529 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800530 }
531
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800532 @GuardedBy("mLock")
533 private void onBackgroundThrottleWhitelistChangedLocked() {
534 String setting = Settings.Global.getString(
535 mContext.getContentResolver(),
536 Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
537 if (setting == null) {
538 setting = "";
539 }
540
541 mBackgroundThrottlePackageWhitelist.clear();
542 mBackgroundThrottlePackageWhitelist.addAll(
543 SystemConfig.getInstance().getAllowUnthrottledLocation());
544 mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(",")));
545
546 for (LocationProvider p : mProviders) {
547 applyRequirementsLocked(p);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000548 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800549 }
550
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800551 @GuardedBy("mLock")
552 private void onUserProfilesChangedLocked() {
553 mCurrentUserProfiles = mUserManager.getProfileIdsWithDisabled(mCurrentUserId);
554 }
555
556 @GuardedBy("mLock")
557 private boolean isCurrentProfileLocked(int userId) {
558 return ArrayUtils.contains(mCurrentUserProfiles, userId);
559 }
560
561 @GuardedBy("mLock")
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700562 private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) {
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500563 PackageManager pm = mContext.getPackageManager();
564 String systemPackageName = mContext.getPackageName();
565 ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
566
567 List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
568 new Intent(FUSED_LOCATION_SERVICE_ACTION),
569 PackageManager.GET_META_DATA, mCurrentUserId);
570 for (ResolveInfo rInfo : rInfos) {
571 String packageName = rInfo.serviceInfo.packageName;
572
573 // Check that the signature is in the list of supported sigs. If it's not in
574 // this list the standard provider binding logic won't bind to it.
575 try {
576 PackageInfo pInfo;
577 pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
578 if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
579 Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
580 ", but has wrong signature, ignoring");
581 continue;
582 }
583 } catch (NameNotFoundException e) {
584 Log.e(TAG, "missing package: " + packageName);
585 continue;
586 }
587
588 // Get the version info
589 if (rInfo.serviceInfo.metaData == null) {
590 Log.w(TAG, "Found fused provider without metadata: " + packageName);
591 continue;
592 }
593
594 int version = rInfo.serviceInfo.metaData.getInt(
595 ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
596 if (version == 0) {
597 // This should be the fallback fused location provider.
598
599 // Make sure it's in the system partition.
600 if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
601 if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
602 continue;
603 }
604
605 // Check that the fallback is signed the same as the OS
606 // as a proxy for coreApp="true"
607 if (pm.checkSignatures(systemPackageName, packageName)
608 != PackageManager.SIGNATURE_MATCH) {
gomo48f1a642017-11-10 20:35:46 -0800609 if (D) {
610 Log.d(TAG, "Fallback candidate not signed the same as system: "
611 + packageName);
612 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500613 continue;
614 }
615
616 // Found a valid fallback.
617 if (D) Log.d(TAG, "Found fallback provider: " + packageName);
618 return;
619 } else {
620 if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
621 }
622 }
623
624 throw new IllegalStateException("Unable to find a fused location provider that is in the "
625 + "system partition with version 0 and signed with the platform certificate. "
626 + "Such a package is needed to provide a default fused location provider in the "
627 + "event that no other fused location provider has been installed or is currently "
628 + "available. For example, coreOnly boot mode when decrypting the data "
629 + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
630 }
631
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800632 @GuardedBy("mLock")
633 private void initializeProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700634 // create a passive location provider, which is always enabled
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800635 LocationProvider passiveProviderManager = new LocationProvider(PASSIVE_PROVIDER);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000636 addProviderLocked(passiveProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800637 mPassiveProvider = new PassiveProvider(passiveProviderManager);
638 passiveProviderManager.attachLocked(mPassiveProvider);
Victoria Lease5c24fd02012-10-01 11:00:50 -0700639
Lifu Tang30f95a72016-01-07 23:20:38 -0800640 if (GnssLocationProvider.isSupported()) {
Wei Liu5241a4c2015-05-11 14:00:36 -0700641 // Create a gps location provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800642 LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
643 mRealProviders.add(gnssProviderManager);
644 addProviderLocked(gnssProviderManager);
645
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700646 GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
647 gnssProviderManager,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800648 mHandler.getLooper());
649 gnssProviderManager.attachLocked(gnssProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700650
Lifu Tang9363b942016-02-16 18:07:00 -0800651 mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
Wyatt Rileycf879db2017-01-12 13:57:38 -0800652 mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
Siddharth Raybb608c82017-03-16 11:33:34 -0700653 mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800654 mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
655 mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
Lifu Tang818aa2c2016-02-01 01:52:00 -0800656 mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
657 mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
Lifu Tang30f95a72016-01-07 23:20:38 -0800658 mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700659 }
660
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700661 /*
662 Load package name(s) containing location provider support.
663 These packages can contain services implementing location providers:
664 Geocoder Provider, Network Location Provider, and
665 Fused Location Provider. They will each be searched for
666 service components implementing these providers.
667 The location framework also has support for installation
668 of new location providers at run-time. The new package does not
669 have to be explicitly listed here, however it must have a signature
670 that matches the signature of at least one package on this list.
671 */
672 Resources resources = mContext.getResources();
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500673 String[] pkgs = resources.getStringArray(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700674 com.android.internal.R.array.config_locationProviderPackageNames);
gomo48f1a642017-11-10 20:35:46 -0800675 if (D) {
676 Log.d(TAG, "certificates for location providers pulled from: " +
677 Arrays.toString(pkgs));
678 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500679
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700680 ensureFallbackFusedProviderPresentLocked(pkgs);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700681
682 // bind to network provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800683 LocationProvider networkProviderManager = new LocationProvider(NETWORK_PROVIDER, true);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700684 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
685 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700686 networkProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700687 NETWORK_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700688 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
689 com.android.internal.R.string.config_networkLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700690 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700691 if (networkProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800692 mRealProviders.add(networkProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000693 addProviderLocked(networkProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800694 networkProviderManager.attachLocked(networkProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700695 } else {
gomo48f1a642017-11-10 20:35:46 -0800696 Slog.w(TAG, "no network location provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700697 }
698
699 // bind to fused provider
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800700 LocationProvider fusedProviderManager = new LocationProvider(FUSED_PROVIDER);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700701 LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700702 mContext,
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700703 fusedProviderManager,
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700704 FUSED_LOCATION_SERVICE_ACTION,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700705 com.android.internal.R.bool.config_enableFusedLocationOverlay,
706 com.android.internal.R.string.config_fusedLocationProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700707 com.android.internal.R.array.config_locationProviderPackageNames);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700708 if (fusedProvider != null) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800709 mRealProviders.add(fusedProviderManager);
Soonil Nagarkar68257742019-01-09 19:42:34 +0000710 addProviderLocked(fusedProviderManager);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800711 fusedProviderManager.attachLocked(fusedProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700712 } else {
713 Slog.e(TAG, "no fused location provider found",
714 new IllegalStateException("Location service needs a fused location provider"));
715 }
716
717 // bind to geocoder provider
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700718 mGeocodeProvider = GeocoderProxy.createAndBind(mContext,
719 com.android.internal.R.bool.config_enableGeocoderOverlay,
720 com.android.internal.R.string.config_geocoderProviderPackageName,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700721 com.android.internal.R.array.config_locationProviderPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700722 if (mGeocodeProvider == null) {
gomo48f1a642017-11-10 20:35:46 -0800723 Slog.e(TAG, "no geocoder provider found");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700724 }
Jaikumar Ganesh8ce470d2013-04-03 12:22:18 -0700725
destradaaf9a274c2014-07-25 15:11:56 -0700726 // bind to geofence provider
727 GeofenceProxy provider = GeofenceProxy.createAndBind(
gomo48f1a642017-11-10 20:35:46 -0800728 mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
destradaaf9a274c2014-07-25 15:11:56 -0700729 com.android.internal.R.string.config_geofenceProviderPackageName,
730 com.android.internal.R.array.config_locationProviderPackageNames,
Wei Liu5241a4c2015-05-11 14:00:36 -0700731 mGpsGeofenceProxy,
Jiyong Park4cc3a1c2018-03-08 16:43:07 +0900732 null);
destradaaf9a274c2014-07-25 15:11:56 -0700733 if (provider == null) {
gomo48f1a642017-11-10 20:35:46 -0800734 Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
destradaa0682809a2013-08-12 18:50:30 -0700735 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900736
737 String[] testProviderStrings = resources.getStringArray(
738 com.android.internal.R.array.config_testLocationProviders);
739 for (String testProviderString : testProviderStrings) {
740 String fragments[] = testProviderString.split(",");
741 String name = fragments[0].trim();
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900742 ProviderProperties properties = new ProviderProperties(
743 Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
744 Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
745 Boolean.parseBoolean(fragments[3]) /* requiresCell */,
746 Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
747 Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
748 Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
749 Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
750 Integer.parseInt(fragments[8]) /* powerRequirement */,
751 Integer.parseInt(fragments[9]) /* accuracy */);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800752 LocationProvider testProviderManager = new LocationProvider(name);
753 addProviderLocked(testProviderManager);
754 new MockProvider(testProviderManager, properties);
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +0900755 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700756 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700757
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800758 @GuardedBy("mLock")
759 private void onUserChangedLocked(int userId) {
Jianzheng Zhoud5c69462013-10-10 14:02:09 +0800760 if (mCurrentUserId == userId) {
761 return;
762 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800763
764 // this call has the side effect of forcing a write to the LOCATION_MODE setting in an OS
765 // upgrade case, and ensures that if anyone checks the LOCATION_MODE setting directly, they
766 // will see it in an appropriate state (at least after that user becomes foreground for the
767 // first time...)
768 isLocationEnabledForUser(userId);
769
770 // let providers know the current user is on the way out before changing the user
771 for (LocationProvider p : mProviders) {
772 p.onUserChangingLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +0000773 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800774
775 mCurrentUserId = userId;
776 onUserProfilesChangedLocked();
777
778 mBlacklist.switchUser(userId);
779
780 // if the user changes, per-user settings may also have changed
781 onLocationModeChangedLocked(false);
782 onProviderAllowedChangedLocked(false);
Victoria Lease38389b62012-09-30 11:44:22 -0700783 }
784
Soonil Nagarkar681d7112017-02-23 17:14:16 -0800785 private static final class Identity {
786 final int mUid;
787 final int mPid;
788 final String mPackageName;
789
790 Identity(int uid, int pid, String packageName) {
791 mUid = uid;
792 mPid = pid;
793 mPackageName = packageName;
794 }
795 }
796
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700797 private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
798
799 private final String mName;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700800
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800801 // whether this provider should respect LOCATION_PROVIDERS_ALLOWED (ie gps and network)
802 private final boolean mIsManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700803
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800804 // remember to clear binder identity before invoking any provider operation
805 @GuardedBy("mLock")
806 @Nullable protected AbstractLocationProvider mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700807
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800808 @GuardedBy("mLock")
809 private boolean mUseable; // combined state
810 @GuardedBy("mLock")
811 private boolean mAllowed; // state of LOCATION_PROVIDERS_ALLOWED
812 @GuardedBy("mLock")
813 private boolean mEnabled; // state of provider
814
815 @GuardedBy("mLock")
816 @Nullable private ProviderProperties mProperties;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700817
818 private LocationProvider(String name) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800819 this(name, false);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700820 }
821
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800822 private LocationProvider(String name, boolean isManagedBySettings) {
823 mName = name;
824 mIsManagedBySettings = isManagedBySettings;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700825
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800826 mProvider = null;
827 mUseable = false;
828 mAllowed = !mIsManagedBySettings;
829 mEnabled = false;
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700830 mProperties = null;
831 }
832
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800833 @GuardedBy("mLock")
834 public void attachLocked(AbstractLocationProvider provider) {
835 checkNotNull(provider);
836 checkState(mProvider == null);
837 mProvider = provider;
838
839 onUseableChangedLocked();
840 }
841
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700842 public String getName() {
843 return mName;
844 }
845
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800846 @GuardedBy("mLock")
847 @Nullable
848 public String getPackageLocked() {
849 if (mProvider == null) {
850 return null;
851 } else if (mProvider instanceof LocationProviderProxy) {
852 // safe to not clear binder context since this doesn't call into the actual provider
853 return ((LocationProviderProxy) mProvider).getConnectedPackageName();
854 } else {
855 return mContext.getPackageName();
856 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700857 }
858
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800859 public boolean isMock() {
860 return false;
861 }
862
863 @GuardedBy("mLock")
864 public boolean isPassiveLocked() {
865 return mProvider == mPassiveProvider;
866 }
867
868 @GuardedBy("mLock")
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700869 @Nullable
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800870 public ProviderProperties getPropertiesLocked() {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700871 return mProperties;
872 }
873
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800874 @GuardedBy("mLock")
875 public void setRequestLocked(ProviderRequest request, WorkSource workSource) {
876 if (mProvider != null) {
877 long identity = Binder.clearCallingIdentity();
878 try {
879 mProvider.setRequest(request, workSource);
880 } finally {
881 Binder.restoreCallingIdentity(identity);
882 }
883 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700884 }
885
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800886 @GuardedBy("mLock")
887 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700888 pw.println(mName + " provider:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800889 if (isMock()) {
890 pw.println(" mock=true");
891 }
892 pw.println(" attached=" + (mProvider != null));
893 if (mIsManagedBySettings) {
894 pw.println(" allowed=" + mAllowed);
895 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700896 pw.println(" enabled=" + mEnabled);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800897 pw.println(" useable=" + mUseable);
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700898 pw.println(" properties=" + mProperties);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800899
900 if (mProvider != null) {
901 long identity = Binder.clearCallingIdentity();
902 try {
903 mProvider.dump(fd, pw, args);
904 } finally {
905 Binder.restoreCallingIdentity(identity);
906 }
907 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700908 }
909
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800910 @GuardedBy("mLock")
911 public long getStatusUpdateTimeLocked() {
912 if (mProvider != null) {
913 long identity = Binder.clearCallingIdentity();
914 try {
915 return mProvider.getStatusUpdateTime();
916 } finally {
917 Binder.restoreCallingIdentity(identity);
918 }
919 } else {
920 return 0;
921 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700922 }
923
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800924 @GuardedBy("mLock")
925 public int getStatusLocked(Bundle extras) {
926 if (mProvider != null) {
927 long identity = Binder.clearCallingIdentity();
928 try {
929 return mProvider.getStatus(extras);
930 } finally {
931 Binder.restoreCallingIdentity(identity);
932 }
933 } else {
934 return AVAILABLE;
935 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700936 }
937
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800938 @GuardedBy("mLock")
939 public void sendExtraCommandLocked(String command, Bundle extras) {
940 if (mProvider != null) {
941 long identity = Binder.clearCallingIdentity();
942 try {
943 mProvider.sendExtraCommand(command, extras);
944 } finally {
945 Binder.restoreCallingIdentity(identity);
946 }
947 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700948 }
949
950 // called from any thread
951 @Override
952 public void onReportLocation(Location location) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800953 // no security check necessary because this is coming from an internal-only interface
954 // move calls coming from below LMS onto a different thread to avoid deadlock
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -0800955 mHandler.post(() -> {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800956 synchronized (mLock) {
957 handleLocationChangedLocked(location, this);
958 }
959 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700960 }
961
962 // called from any thread
963 @Override
964 public void onReportLocation(List<Location> locations) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800965 // move calls coming from below LMS onto a different thread to avoid deadlock
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -0800966 mHandler.post(() -> {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800967 synchronized (mLock) {
968 LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
969 if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
970 Slog.w(TAG, "reportLocationBatch() called without user permission");
971 return;
972 }
973
974 if (mGnssBatchingCallback == null) {
975 Slog.e(TAG, "reportLocationBatch() called without active Callback");
976 return;
977 }
978
979 try {
980 mGnssBatchingCallback.onLocationBatch(locations);
981 } catch (RemoteException e) {
982 Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
983 }
984 }
985 });
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700986 }
987
988 // called from any thread
989 @Override
990 public void onSetEnabled(boolean enabled) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800991 // move calls coming from below LMS onto a different thread to avoid deadlock
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -0800992 mHandler.post(() -> {
Soonil Nagarkar68257742019-01-09 19:42:34 +0000993 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800994 if (enabled == mEnabled) {
995 return;
Soonil Nagarkar68257742019-01-09 19:42:34 +0000996 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -0700997
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -0800998 mEnabled = enabled;
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -0800999
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001000 // update provider allowed settings to reflect enabled status
1001 if (mIsManagedBySettings) {
1002 if (mEnabled && !mAllowed) {
1003 Settings.Secure.putStringForUser(
1004 mContext.getContentResolver(),
1005 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1006 "+" + mName,
1007 mCurrentUserId);
1008 } else if (!mEnabled && mAllowed) {
1009 Settings.Secure.putStringForUser(
1010 mContext.getContentResolver(),
1011 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1012 "-" + mName,
1013 mCurrentUserId);
1014 }
1015 }
1016
1017 onUseableChangedLocked();
1018 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001019 });
1020 }
1021
1022 @Override
1023 public void onSetProperties(ProviderProperties properties) {
Soonil Nagarkar66c0bac2019-01-15 13:36:44 -08001024 // because this does not invoke any other methods which might result in calling back
1025 // into the location provider, it is safe to run this on the calling thread. it is also
1026 // currently necessary to run this on the calling thread to ensure that property changes
1027 // are publicly visibly immediately, ie for mock providers which are created.
1028 synchronized (mLock) {
1029 mProperties = properties;
1030 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001031 }
1032
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001033 @GuardedBy("mLock")
1034 public void onLocationModeChangedLocked() {
1035 onUseableChangedLocked();
1036 }
1037
1038 private boolean isAllowed() {
1039 return isAllowedForUser(mCurrentUserId);
1040 }
1041
1042 private boolean isAllowedForUser(int userId) {
1043 String allowedProviders = Settings.Secure.getStringForUser(
1044 mContext.getContentResolver(),
1045 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1046 userId);
1047 return TextUtils.delimitedStringContains(allowedProviders, ',', mName);
1048 }
1049
1050 @GuardedBy("mLock")
1051 public void onAllowedChangedLocked() {
1052 if (mIsManagedBySettings) {
1053 boolean allowed = isAllowed();
1054 if (allowed == mAllowed) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001055 return;
1056 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001057 mAllowed = allowed;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001058
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001059 // make a best effort to keep the setting matching the real enabled state of the
1060 // provider so that legacy applications aren't broken.
1061 if (mAllowed && !mEnabled) {
1062 Settings.Secure.putStringForUser(
1063 mContext.getContentResolver(),
1064 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
1065 "-" + mName,
1066 mCurrentUserId);
1067 }
1068
1069 onUseableChangedLocked();
1070 }
1071 }
1072
1073 @GuardedBy("mLock")
1074 public boolean isUseableLocked() {
1075 return isUseableForUserLocked(mCurrentUserId);
1076 }
1077
1078 @GuardedBy("mLock")
1079 public boolean isUseableForUserLocked(int userId) {
1080 return userId == mCurrentUserId && mUseable;
1081 }
1082
1083 @GuardedBy("mLock")
1084 public void onUseableChangedLocked() {
1085 // if any property that contributes to "useability" here changes state, it MUST result
1086 // in a direct or indrect call to onUseableChangedLocked. this allows the provider to
1087 // guarantee that it will always eventually reach the correct state.
1088 boolean useable = mProvider != null
1089 && mProviders.contains(this) && isLocationEnabled() && mAllowed && mEnabled;
1090 if (useable == mUseable) {
1091 return;
1092 }
1093 mUseable = useable;
1094
1095 if (!mUseable) {
1096 // If any provider has been disabled, clear all last locations for all
1097 // providers. This is to be on the safe side in case a provider has location
1098 // derived from this disabled provider.
1099 mLastLocation.clear();
1100 mLastLocationCoarseInterval.clear();
1101 }
1102
1103 updateProviderUseableLocked(this);
1104 }
1105
1106 @GuardedBy("mLock")
1107 public void onUserChangingLocked() {
1108 // when the user is about to change, we set this provider to un-useable, and notify all
1109 // of the current user clients. when the user is finished changing, useability will be
1110 // updated back via onLocationModeChanged() and onAllowedChanged().
1111 mUseable = false;
1112 updateProviderUseableLocked(this);
1113 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001114 }
1115
1116 private class MockLocationProvider extends LocationProvider {
1117
1118 private MockLocationProvider(String name) {
1119 super(name);
1120 }
1121
1122 @Override
1123 public void attachLocked(AbstractLocationProvider provider) {
1124 checkState(provider instanceof MockProvider);
1125 super.attachLocked(provider);
1126 }
1127
1128 public boolean isMock() {
1129 return true;
1130 }
1131
1132 @GuardedBy("mLock")
1133 public void setEnabledLocked(boolean enabled) {
1134 if (mProvider != null) {
1135 long identity = Binder.clearCallingIdentity();
1136 try {
1137 ((MockProvider) mProvider).setEnabled(enabled);
1138 } finally {
1139 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00001140 }
1141 }
1142 }
1143
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001144 @GuardedBy("mLock")
1145 public void setLocationLocked(Location location) {
1146 if (mProvider != null) {
1147 long identity = Binder.clearCallingIdentity();
1148 try {
1149 ((MockProvider) mProvider).setLocation(location);
1150 } finally {
1151 Binder.restoreCallingIdentity(identity);
1152 }
1153 }
1154 }
1155
1156 @GuardedBy("mLock")
1157 public void setStatusLocked(int status, Bundle extras, long updateTime) {
1158 if (mProvider != null) {
1159 long identity = Binder.clearCallingIdentity();
1160 try {
1161 ((MockProvider) mProvider).setStatus(status, extras, updateTime);
1162 } finally {
1163 Binder.restoreCallingIdentity(identity);
1164 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001165 }
1166 }
1167 }
1168
Victoria Lease38389b62012-09-30 11:44:22 -07001169 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001170 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
1171 * location updates.
1172 */
Mike Lockwood48f17512009-04-23 09:12:08 -07001173 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Yu-Han Yang24189822018-07-11 15:24:11 -07001174 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001175 final Identity mIdentity;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001176 private final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001177
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001178 private final ILocationListener mListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 final PendingIntent mPendingIntent;
David Christie82edc9b2013-07-19 11:31:42 -07001180 final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001181 private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
1182 private final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001183
gomo48f1a642017-11-10 20:35:46 -08001184 final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
Nick Pellyf1be6862012-05-15 10:53:42 -07001185
David Christie0b837452013-07-29 16:02:13 -07001186 // True if app ops has started monitoring this receiver for locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001187 private boolean mOpMonitoring;
David Christie0b837452013-07-29 16:02:13 -07001188 // True if app ops has started monitoring this receiver for high power (gps) locations.
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001189 private boolean mOpHighPowerMonitoring;
1190 private int mPendingBroadcasts;
Victoria Lease0aa28602013-05-29 15:28:26 -07001191 PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001193 private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07001194 String packageName, WorkSource workSource, boolean hideFromAppOps) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001197 if (listener != null) {
1198 mKey = listener.asBinder();
1199 } else {
1200 mKey = intent;
1201 }
Victoria Lease37425c32012-10-16 16:08:48 -07001202 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001203 mIdentity = new Identity(uid, pid, packageName);
Narayan Kamath32684dd2018-01-08 17:32:51 +00001204 if (workSource != null && workSource.isEmpty()) {
David Christie82edc9b2013-07-19 11:31:42 -07001205 workSource = null;
1206 }
1207 mWorkSource = workSource;
David Christie40e57822013-07-30 11:36:48 -07001208 mHideFromAppOps = hideFromAppOps;
Victoria Lease0aa28602013-05-29 15:28:26 -07001209
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001210 updateMonitoring(true);
1211
Victoria Lease0aa28602013-05-29 15:28:26 -07001212 // construct/configure wakelock
1213 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
David Christie82edc9b2013-07-19 11:31:42 -07001214 if (workSource == null) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001215 workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07001216 }
1217 mWakeLock.setWorkSource(workSource);
Yu-Han Yang24189822018-07-11 15:24:11 -07001218
1219 // For a non-reference counted wakelock, each acquire will reset the timeout, and we
1220 // only need to release it once.
1221 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 }
1223
1224 @Override
1225 public boolean equals(Object otherObj) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001226 return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 }
1228
1229 @Override
1230 public int hashCode() {
1231 return mKey.hashCode();
1232 }
Mike Lockwood3681f262009-05-12 10:52:03 -04001233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 @Override
1235 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001236 StringBuilder s = new StringBuilder();
1237 s.append("Reciever[");
1238 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001240 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001242 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001244 for (String p : mUpdateRecords.keySet()) {
1245 s.append(" ").append(mUpdateRecords.get(p).toString());
1246 }
Wei Wangdd070f22018-06-21 11:29:40 -07001247 s.append(" monitoring location: ").append(mOpMonitoring);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001248 s.append("]");
1249 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 }
1251
David Christie15b31912013-08-13 15:54:32 -07001252 /**
1253 * Update AppOp monitoring for this receiver.
1254 *
1255 * @param allow If true receiver is currently active, if false it's been removed.
1256 */
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001257 public void updateMonitoring(boolean allow) {
David Christie40e57822013-07-30 11:36:48 -07001258 if (mHideFromAppOps) {
1259 return;
1260 }
1261
David Christie15b31912013-08-13 15:54:32 -07001262 boolean requestingLocation = false;
1263 boolean requestingHighPowerLocation = false;
1264 if (allow) {
1265 // See if receiver has any enabled update records. Also note if any update records
1266 // are high power (has a high power provider with an interval under a threshold).
1267 for (UpdateRecord updateRecord : mUpdateRecords.values()) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001268 LocationProvider provider = getLocationProviderLocked(updateRecord.mProvider);
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001269 if (provider == null) {
1270 continue;
1271 }
1272 if (!provider.isUseableLocked()
1273 && !updateRecord.mRealRequest.isLocationSettingsIgnored()) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001274 continue;
1275 }
1276
1277 requestingLocation = true;
1278 ProviderProperties properties = provider.getPropertiesLocked();
1279 if (properties != null
1280 && properties.mPowerRequirement == Criteria.POWER_HIGH
1281 && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
1282 requestingHighPowerLocation = true;
1283 break;
David Christie15b31912013-08-13 15:54:32 -07001284 }
1285 }
1286 }
1287
David Christie0b837452013-07-29 16:02:13 -07001288 // First update monitoring of any location request (including high power).
David Christie15b31912013-08-13 15:54:32 -07001289 mOpMonitoring = updateMonitoring(
1290 requestingLocation,
1291 mOpMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001292 AppOpsManager.OP_MONITOR_LOCATION);
1293
1294 // Now update monitoring of high power requests only.
David Christiec750c1f2013-08-08 12:56:57 -07001295 boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
David Christie15b31912013-08-13 15:54:32 -07001296 mOpHighPowerMonitoring = updateMonitoring(
1297 requestingHighPowerLocation,
1298 mOpHighPowerMonitoring,
David Christie0b837452013-07-29 16:02:13 -07001299 AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
David Christiec750c1f2013-08-08 12:56:57 -07001300 if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
David Christie15b31912013-08-13 15:54:32 -07001301 // Send an intent to notify that a high power request has been added/removed.
David Christiec750c1f2013-08-08 12:56:57 -07001302 Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
1303 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1304 }
David Christie0b837452013-07-29 16:02:13 -07001305 }
1306
1307 /**
1308 * Update AppOps monitoring for a single location request and op type.
1309 *
gomo48f1a642017-11-10 20:35:46 -08001310 * @param allowMonitoring True if monitoring is allowed for this request/op.
David Christie0b837452013-07-29 16:02:13 -07001311 * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
gomo48f1a642017-11-10 20:35:46 -08001312 * @param op AppOps code for the op to update.
David Christie0b837452013-07-29 16:02:13 -07001313 * @return True if monitoring is on for this request/op after updating.
1314 */
1315 private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
1316 int op) {
1317 if (!currentlyMonitoring) {
1318 if (allowMonitoring) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001319 return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001320 == AppOpsManager.MODE_ALLOWED;
1321 }
1322 } else {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001323 if (!allowMonitoring
Wei Wangdd070f22018-06-21 11:29:40 -07001324 || mAppOps.noteOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
David Christie0b837452013-07-29 16:02:13 -07001325 != AppOpsManager.MODE_ALLOWED) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08001326 mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
David Christie0b837452013-07-29 16:02:13 -07001327 return false;
1328 }
1329 }
1330
1331 return currentlyMonitoring;
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07001332 }
1333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 public boolean isListener() {
1335 return mListener != null;
1336 }
1337
1338 public boolean isPendingIntent() {
1339 return mPendingIntent != null;
1340 }
1341
1342 public ILocationListener getListener() {
1343 if (mListener != null) {
1344 return mListener;
1345 }
1346 throw new IllegalStateException("Request for non-existent listener");
1347 }
1348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
1350 if (mListener != null) {
1351 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001352 synchronized (this) {
1353 // synchronize to ensure incrementPendingBroadcastsLocked()
1354 // is called before decrementPendingBroadcasts()
1355 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -07001356 // call this after broadcasting so we do not increment
1357 // if we throw an exeption.
1358 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001359 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 } catch (RemoteException e) {
1361 return false;
1362 }
1363 } else {
1364 Intent statusChanged = new Intent();
Victoria Lease61ecb022012-11-13 15:12:51 -08001365 statusChanged.putExtras(new Bundle(extras));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
1367 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001368 synchronized (this) {
1369 // synchronize to ensure incrementPendingBroadcastsLocked()
1370 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001371 mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001372 getResolutionPermission(mAllowedResolutionLevel),
1373 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001374 // call this after broadcasting so we do not increment
1375 // if we throw an exeption.
1376 incrementPendingBroadcastsLocked();
1377 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 } catch (PendingIntent.CanceledException e) {
1379 return false;
1380 }
1381 }
1382 return true;
1383 }
1384
1385 public boolean callLocationChangedLocked(Location location) {
1386 if (mListener != null) {
1387 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001388 synchronized (this) {
1389 // synchronize to ensure incrementPendingBroadcastsLocked()
1390 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c5406a2012-11-29 16:18:01 -08001391 mListener.onLocationChanged(new Location(location));
Nick Pellye0fd6932012-07-11 10:26:13 -07001392 // call this after broadcasting so we do not increment
1393 // if we throw an exeption.
1394 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001395 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 } catch (RemoteException e) {
1397 return false;
1398 }
1399 } else {
1400 Intent locationChanged = new Intent();
gomo48f1a642017-11-10 20:35:46 -08001401 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
1402 new Location(location));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001404 synchronized (this) {
1405 // synchronize to ensure incrementPendingBroadcastsLocked()
1406 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001407 mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001408 getResolutionPermission(mAllowedResolutionLevel),
1409 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001410 // call this after broadcasting so we do not increment
1411 // if we throw an exeption.
1412 incrementPendingBroadcastsLocked();
1413 }
1414 } catch (PendingIntent.CanceledException e) {
1415 return false;
1416 }
1417 }
1418 return true;
1419 }
1420
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001421 private boolean callProviderEnabledLocked(String provider, boolean enabled) {
David Christie15b31912013-08-13 15:54:32 -07001422 // First update AppOp monitoring.
1423 // An app may get/lose location access as providers are enabled/disabled.
1424 updateMonitoring(true);
1425
Mike Lockwood48f17512009-04-23 09:12:08 -07001426 if (mListener != null) {
1427 try {
1428 synchronized (this) {
1429 // synchronize to ensure incrementPendingBroadcastsLocked()
1430 // is called before decrementPendingBroadcasts()
1431 if (enabled) {
1432 mListener.onProviderEnabled(provider);
1433 } else {
1434 mListener.onProviderDisabled(provider);
1435 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001436 // call this after broadcasting so we do not increment
1437 // if we throw an exeption.
1438 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001439 }
1440 } catch (RemoteException e) {
1441 return false;
1442 }
1443 } else {
1444 Intent providerIntent = new Intent();
1445 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
1446 try {
1447 synchronized (this) {
1448 // synchronize to ensure incrementPendingBroadcastsLocked()
1449 // is called before decrementPendingBroadcasts()
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001450 mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
Lifu Tang519f0d02018-04-12 16:39:39 -07001451 getResolutionPermission(mAllowedResolutionLevel),
1452 PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
Mike Lockwood48f17512009-04-23 09:12:08 -07001453 // call this after broadcasting so we do not increment
1454 // if we throw an exeption.
1455 incrementPendingBroadcastsLocked();
1456 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 } catch (PendingIntent.CanceledException e) {
1458 return false;
1459 }
1460 }
1461 return true;
1462 }
1463
Nick Pellyf1be6862012-05-15 10:53:42 -07001464 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001466 if (D) Log.d(TAG, "Location listener died");
1467
Soonil Nagarkar68257742019-01-09 19:42:34 +00001468 synchronized (mLock) {
1469 removeUpdatesLocked(this);
1470 }
1471 synchronized (this) {
1472 clearPendingBroadcastsLocked();
1473 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001474 }
1475
Nick Pellye0fd6932012-07-11 10:26:13 -07001476 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -07001477 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1478 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001479 synchronized (this) {
1480 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -07001481 }
1482 }
1483
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001484 // this must be called while synchronized by caller in a synchronized block
1485 // containing the sending of the broadcaset
1486 private void incrementPendingBroadcastsLocked() {
Yu-Han Yang24189822018-07-11 15:24:11 -07001487 mPendingBroadcasts++;
1488 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001489 }
1490
1491 private void decrementPendingBroadcastsLocked() {
1492 if (--mPendingBroadcasts == 0) {
Victoria Lease0aa28602013-05-29 15:28:26 -07001493 if (mWakeLock.isHeld()) {
1494 mWakeLock.release();
1495 }
1496 }
1497 }
1498
1499 public void clearPendingBroadcastsLocked() {
1500 if (mPendingBroadcasts > 0) {
1501 mPendingBroadcasts = 0;
1502 if (mWakeLock.isHeld()) {
1503 mWakeLock.release();
1504 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001505 }
1506 }
1507 }
1508
Nick Pellye0fd6932012-07-11 10:26:13 -07001509 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001510 public void locationCallbackFinished(ILocationListener listener) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001511 //Do not use getReceiverLocked here as that will add the ILocationListener to
Joshua Bartel080b61b2009-10-05 12:44:46 -04001512 //the receiver list if it is not found. If it is not found then the
1513 //LocationListener was removed when it had a pending broadcast and should
1514 //not be added back.
Soonil Nagarkar68257742019-01-09 19:42:34 +00001515 synchronized (mLock) {
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001516 IBinder binder = listener.asBinder();
1517 Receiver receiver = mReceivers.get(binder);
1518 if (receiver != null) {
1519 synchronized (receiver) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001520 // so wakelock calls will succeed
1521 long identity = Binder.clearCallingIdentity();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001522 try {
1523 receiver.decrementPendingBroadcastsLocked();
1524 } finally {
1525 Binder.restoreCallingIdentity(identity);
1526 }
David Christie2ff96af2014-01-30 16:09:37 -08001527 }
Dianne Hackbornf5fdca92013-06-05 14:53:33 -07001528 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00001529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 }
1531
Lifu Tang82f893d2016-01-21 18:15:33 -08001532 @Override
Lifu Tang9363b942016-02-16 18:07:00 -08001533 public int getGnssYearOfHardware() {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001534 if (mGnssSystemInfoProvider != null) {
Lifu Tang9363b942016-02-16 18:07:00 -08001535 return mGnssSystemInfoProvider.getGnssYearOfHardware();
Lifu Tang82f893d2016-01-21 18:15:33 -08001536 } else {
1537 return 0;
1538 }
1539 }
1540
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001541 @Override
Wyatt Riley49097c02018-03-15 09:14:43 -07001542 @Nullable
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001543 public String getGnssHardwareModelName() {
1544 if (mGnssSystemInfoProvider != null) {
1545 return mGnssSystemInfoProvider.getGnssHardwareModelName();
1546 } else {
Wyatt Riley49097c02018-03-15 09:14:43 -07001547 return null;
Wyatt Rileyd87cf912017-12-05 09:31:52 -08001548 }
1549 }
1550
Wyatt Rileycf879db2017-01-12 13:57:38 -08001551 private boolean hasGnssPermissions(String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001552 synchronized (mLock) {
1553 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1554 checkResolutionLevelIsSufficientForProviderUseLocked(
1555 allowedResolutionLevel,
1556 GPS_PROVIDER);
Wyatt Rileycf879db2017-01-12 13:57:38 -08001557
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001558 int pid = Binder.getCallingPid();
1559 int uid = Binder.getCallingUid();
1560 long identity = Binder.clearCallingIdentity();
1561 try {
1562 return checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
1563 } finally {
1564 Binder.restoreCallingIdentity(identity);
1565 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001566 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001567 }
1568
Wyatt Rileycf879db2017-01-12 13:57:38 -08001569 @Override
1570 public int getGnssBatchSize(String packageName) {
1571 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1572 "Location Hardware permission not granted to access hardware batching");
1573
1574 if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
Yu-Han Yang3557cc72018-03-21 12:48:36 -07001575 return mGnssBatchingProvider.getBatchSize();
Wyatt Rileycf879db2017-01-12 13:57:38 -08001576 } else {
1577 return 0;
1578 }
1579 }
1580
Wyatt Rileycf879db2017-01-12 13:57:38 -08001581 @Override
1582 public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
1583 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1584 "Location Hardware permission not granted to access hardware batching");
1585
1586 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1587 return false;
1588 }
1589
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001590 synchronized (mLock) {
1591 mGnssBatchingCallback = callback;
1592 mGnssBatchingDeathCallback = new LinkedCallback(callback);
1593 try {
1594 callback.asBinder().linkToDeath(mGnssBatchingDeathCallback, 0 /* flags */);
1595 } catch (RemoteException e) {
1596 // if the remote process registering the listener is already dead, just swallow the
1597 // exception and return
1598 Log.e(TAG, "Remote listener already died.", e);
1599 return false;
1600 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001601
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001602 return true;
1603 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001604 }
1605
1606 private class LinkedCallback implements IBinder.DeathRecipient {
1607 private final IBatchedLocationCallback mCallback;
1608
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001609 private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08001610 mCallback = callback;
1611 }
1612
1613 @NonNull
1614 public IBatchedLocationCallback getUnderlyingListener() {
1615 return mCallback;
1616 }
1617
1618 @Override
1619 public void binderDied() {
1620 Log.d(TAG, "Remote Batching Callback died: " + mCallback);
1621 stopGnssBatch();
1622 removeGnssBatchingCallback();
1623 }
1624 }
1625
Wyatt Rileycf879db2017-01-12 13:57:38 -08001626 @Override
1627 public void removeGnssBatchingCallback() {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001628 synchronized (mLock) {
1629 try {
1630 mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathCallback,
1631 0 /* flags */);
1632 } catch (NoSuchElementException e) {
1633 // if the death callback isn't connected (it should be...), log error, swallow the
1634 // exception and return
1635 Log.e(TAG, "Couldn't unlink death callback.", e);
1636 }
1637 mGnssBatchingCallback = null;
1638 mGnssBatchingDeathCallback = null;
Wyatt Rileycf879db2017-01-12 13:57:38 -08001639 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001640 }
1641
Wyatt Rileycf879db2017-01-12 13:57:38 -08001642 @Override
1643 public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
1644 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1645 "Location Hardware permission not granted to access hardware batching");
1646
1647 if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
1648 return false;
1649 }
1650
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001651 synchronized (mLock) {
1652 if (mGnssBatchingInProgress) {
1653 // Current design does not expect multiple starts to be called repeatedly
1654 Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
1655 // Try to clean up anyway, and continue
1656 stopGnssBatch();
1657 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001658
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001659 mGnssBatchingInProgress = true;
1660 return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
1661 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001662 }
1663
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001664
Wyatt Rileycf879db2017-01-12 13:57:38 -08001665 @Override
1666 public void flushGnssBatch(String packageName) {
1667 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1668 "Location Hardware permission not granted to access hardware batching");
1669
1670 if (!hasGnssPermissions(packageName)) {
1671 Log.e(TAG, "flushGnssBatch called without GNSS permissions");
1672 return;
1673 }
1674
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001675 synchronized (mLock) {
1676 if (!mGnssBatchingInProgress) {
1677 Log.w(TAG, "flushGnssBatch called with no batch in progress");
1678 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001679
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001680 if (mGnssBatchingProvider != null) {
1681 mGnssBatchingProvider.flush();
1682 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08001683 }
1684 }
1685
Wyatt Rileycf879db2017-01-12 13:57:38 -08001686 @Override
1687 public boolean stopGnssBatch() {
1688 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
1689 "Location Hardware permission not granted to access hardware batching");
1690
Soonil Nagarkar68257742019-01-09 19:42:34 +00001691 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001692 if (mGnssBatchingProvider != null) {
1693 mGnssBatchingInProgress = false;
1694 return mGnssBatchingProvider.stop();
1695 } else {
1696 return false;
1697 }
1698 }
1699 }
1700
1701 @GuardedBy("mLock")
1702 private void addProviderLocked(LocationProvider provider) {
1703 Preconditions.checkState(getLocationProviderLocked(provider.getName()) == null);
1704
1705 mProviders.add(provider);
1706
1707 provider.onAllowedChangedLocked(); // allowed state may change while provider was inactive
1708 provider.onUseableChangedLocked();
1709 }
1710
1711 @GuardedBy("mLock")
1712 private void removeProviderLocked(LocationProvider provider) {
1713 if (mProviders.remove(provider)) {
1714 long identity = Binder.clearCallingIdentity();
1715 try {
1716 provider.onUseableChangedLocked();
1717 } finally {
1718 Binder.restoreCallingIdentity(identity);
1719 }
1720 }
1721 }
1722
1723 @GuardedBy("mLock")
1724 @Nullable
1725 private LocationProvider getLocationProviderLocked(String providerName) {
1726 for (LocationProvider provider : mProviders) {
1727 if (providerName.equals(provider.getName())) {
1728 return provider;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001729 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001730 }
1731
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001732 return null;
Maggie2a9409e2018-03-21 11:47:28 -07001733 }
1734
Victoria Lease37425c32012-10-16 16:08:48 -07001735 private String getResolutionPermission(int resolutionLevel) {
1736 switch (resolutionLevel) {
1737 case RESOLUTION_LEVEL_FINE:
1738 return android.Manifest.permission.ACCESS_FINE_LOCATION;
1739 case RESOLUTION_LEVEL_COARSE:
1740 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
1741 default:
1742 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 }
Victoria Leaseda479c52012-10-15 15:24:16 -07001744 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001745
Victoria Lease37425c32012-10-16 16:08:48 -07001746 private int getAllowedResolutionLevel(int pid, int uid) {
1747 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001748 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001749 return RESOLUTION_LEVEL_FINE;
1750 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
Maggieaa080f92018-01-04 15:35:11 -08001751 pid, uid) == PERMISSION_GRANTED) {
Victoria Lease37425c32012-10-16 16:08:48 -07001752 return RESOLUTION_LEVEL_COARSE;
1753 } else {
1754 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -07001755 }
Victoria Lease4fab68b2012-09-13 13:20:59 -07001756 }
1757
Victoria Lease37425c32012-10-16 16:08:48 -07001758 private int getCallerAllowedResolutionLevel() {
1759 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
1760 }
1761
Victoria Lease37425c32012-10-16 16:08:48 -07001762 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
1763 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -07001764 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
1765 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 }
1767
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001768 @GuardedBy("mLock")
1769 private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
1770 if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001771 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001772 return RESOLUTION_LEVEL_FINE;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001773 } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -07001774 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001775 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001776 } else {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001777 for (LocationProvider lp : mProviders) {
1778 if (!lp.getName().equals(provider)) {
1779 continue;
1780 }
1781
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001782 ProviderProperties properties = lp.getPropertiesLocked();
Laurent Tu941221c2012-10-04 14:21:52 -07001783 if (properties != null) {
1784 if (properties.mRequiresSatellite) {
1785 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -07001786 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -07001787 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
1788 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -07001789 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -07001790 }
1791 }
1792 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001793 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001794
Victoria Lease37425c32012-10-16 16:08:48 -07001795 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -07001796 }
1797
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001798 @GuardedBy("mLock")
1799 private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
Victoria Lease37425c32012-10-16 16:08:48 -07001800 String providerName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001801 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
Victoria Lease37425c32012-10-16 16:08:48 -07001802 if (allowedResolutionLevel < requiredResolutionLevel) {
1803 switch (requiredResolutionLevel) {
1804 case RESOLUTION_LEVEL_FINE:
1805 throw new SecurityException("\"" + providerName + "\" location provider " +
1806 "requires ACCESS_FINE_LOCATION permission.");
1807 case RESOLUTION_LEVEL_COARSE:
1808 throw new SecurityException("\"" + providerName + "\" location provider " +
1809 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
1810 default:
1811 throw new SecurityException("Insufficient permission for \"" + providerName +
1812 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -07001813 }
1814 }
Victoria Lease8dbb6342012-09-21 16:55:53 -07001815 }
1816
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001817 public static int resolutionLevelToOp(int allowedResolutionLevel) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001818 if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
1819 if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001820 return AppOpsManager.OP_COARSE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001821 } else {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001822 return AppOpsManager.OP_FINE_LOCATION;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001823 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001824 }
1825 return -1;
1826 }
1827
Wei Wangb86334f2018-07-03 16:33:24 -07001828 private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001829 switch (allowedResolutionLevel) {
Wei Wangb86334f2018-07-03 16:33:24 -07001830 case RESOLUTION_LEVEL_COARSE:
1831 return AppOpsManager.OPSTR_COARSE_LOCATION;
1832 case RESOLUTION_LEVEL_FINE:
1833 return AppOpsManager.OPSTR_FINE_LOCATION;
1834 case RESOLUTION_LEVEL_NONE:
1835 // The client is not allowed to get any location, so both FINE and COARSE ops will
1836 // be denied. Pick the most restrictive one to be safe.
1837 return AppOpsManager.OPSTR_FINE_LOCATION;
1838 default:
1839 // Use the most restrictive ops if not sure.
1840 return AppOpsManager.OPSTR_FINE_LOCATION;
1841 }
1842 }
1843
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001844 private boolean reportLocationAccessNoThrow(
David Christieb870dbf2015-06-22 12:42:53 -07001845 int pid, int uid, String packageName, int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001846 int op = resolutionLevelToOp(allowedResolutionLevel);
1847 if (op >= 0) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001848 if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
1849 return false;
1850 }
1851 }
David Christieb870dbf2015-06-22 12:42:53 -07001852
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001853 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001854 }
1855
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001856 private boolean checkLocationAccess(int pid, int uid, String packageName,
1857 int allowedResolutionLevel) {
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08001858 int op = resolutionLevelToOp(allowedResolutionLevel);
1859 if (op >= 0) {
Wei Wangdd070f22018-06-21 11:29:40 -07001860 if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
Dianne Hackborn35654b62013-01-14 17:38:02 -08001861 return false;
1862 }
1863 }
David Christieb870dbf2015-06-22 12:42:53 -07001864
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001865 return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
Dianne Hackborn35654b62013-01-14 17:38:02 -08001866 }
1867
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001868 /**
Maggie91e630c2018-01-24 17:31:46 -08001869 * Returns all providers by name, including passive and the ones that are not permitted to
1870 * be accessed by the calling activity or are currently disabled, but excluding fused.
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001871 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001872 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873 public List<String> getAllProviders() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001874 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001875 ArrayList<String> providers = new ArrayList<>(mProviders.size());
Soonil Nagarkar68257742019-01-09 19:42:34 +00001876 for (LocationProvider provider : mProviders) {
1877 String name = provider.getName();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001878 if (FUSED_PROVIDER.equals(name)) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001879 continue;
1880 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001881 providers.add(name);
Maggie91e630c2018-01-24 17:31:46 -08001882 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001883 return providers;
Maggie91e630c2018-01-24 17:31:46 -08001884 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 }
1886
Mike Lockwood03ca2162010-04-01 08:10:09 -07001887 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001888 * Return all providers by name, that match criteria and are optionally
1889 * enabled.
1890 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001891 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001892 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001893 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -07001894 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001895 synchronized (mLock) {
1896 ArrayList<String> providers = new ArrayList<>(mProviders.size());
1897 for (LocationProvider provider : mProviders) {
1898 String name = provider.getName();
1899 if (FUSED_PROVIDER.equals(name)) {
1900 continue;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001901 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001902 if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
1903 continue;
1904 }
1905 if (enabledOnly && !provider.isUseableLocked()) {
1906 continue;
1907 }
1908 if (criteria != null
1909 && !android.location.LocationProvider.propertiesMeetCriteria(
1910 name, provider.getPropertiesLocked(), criteria)) {
1911 continue;
1912 }
1913 providers.add(name);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001914 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001915 return providers;
Soonil Nagarkar68257742019-01-09 19:42:34 +00001916 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07001917 }
1918
1919 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001920 * Return the name of the best provider given a Criteria object.
1921 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -07001922 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001923 * has been deprecated as well. So this method now uses
1924 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -07001925 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001926 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00001927 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001928 List<String> providers = getProviders(criteria, enabledOnly);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001929 if (providers.isEmpty()) {
1930 providers = getProviders(null, enabledOnly);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08001931 }
1932
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001933 if (!providers.isEmpty()) {
1934 if (providers.contains(GPS_PROVIDER)) {
1935 return GPS_PROVIDER;
1936 } else if (providers.contains(NETWORK_PROVIDER)) {
1937 return NETWORK_PROVIDER;
1938 } else {
1939 return providers.get(0);
1940 }
1941 }
1942
Mike Lockwood03ca2162010-04-01 08:10:09 -07001943 return null;
1944 }
1945
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001946 @GuardedBy("mLock")
1947 private void updateProviderUseableLocked(LocationProvider provider) {
1948 boolean useable = provider.isUseableLocked();
Soonil Nagarkar1575a042018-10-24 17:54:54 -07001949
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001950 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001951
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001952 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 if (records != null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001954 for (UpdateRecord record : records) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001955 if (!isCurrentProfileLocked(
1956 UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
1957 continue;
1958 }
1959
1960 // requests that ignore location settings will never provider notifications
1961 if (record.mRealRequest.isLocationSettingsIgnored()) {
1962 continue;
1963 }
1964
1965 // Sends a notification message to the receiver
1966 if (!record.mReceiver.callProviderEnabledLocked(provider.getName(), useable)) {
1967 if (deadReceivers == null) {
1968 deadReceivers = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08001970 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 }
1973 }
1974
1975 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001976 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00001977 removeUpdatesLocked(deadReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 }
1979 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001980
Soonil Nagarkar68257742019-01-09 19:42:34 +00001981 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 }
1983
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001984 @GuardedBy("mLock")
1985 private void applyRequirementsLocked(String providerName) {
1986 LocationProvider provider = getLocationProviderLocked(providerName);
1987 if (provider != null) {
1988 applyRequirementsLocked(provider);
1989 }
1990 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001991
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001992 @GuardedBy("mLock")
1993 private void applyRequirementsLocked(LocationProvider provider) {
1994 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001995 WorkSource worksource = new WorkSource();
1996 ProviderRequest providerRequest = new ProviderRequest();
1997
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08001998 long backgroundThrottleInterval;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08001999
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002000 long identity = Binder.clearCallingIdentity();
2001 try {
2002 backgroundThrottleInterval = Settings.Global.getLong(
2003 mContext.getContentResolver(),
2004 Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
2005 DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
2006 } finally {
2007 Binder.restoreCallingIdentity(identity);
2008 }
2009
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002010 if (records != null && !records.isEmpty()) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002011 // initialize the low power mode to true and set to false if any of the records requires
2012 providerRequest.lowPowerMode = true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002013 for (UpdateRecord record : records) {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002014 if (!isCurrentProfileLocked(
2015 UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
2016 continue;
2017 }
2018 if (!checkLocationAccess(
2019 record.mReceiver.mIdentity.mPid,
2020 record.mReceiver.mIdentity.mUid,
2021 record.mReceiver.mIdentity.mPackageName,
2022 record.mReceiver.mAllowedResolutionLevel)) {
2023 continue;
2024 }
2025 if (!provider.isUseableLocked()
2026 && !record.mRealRequest.isLocationSettingsIgnored()) {
2027 continue;
2028 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002029
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002030 LocationRequest locationRequest = record.mRealRequest;
2031 long interval = locationRequest.getInterval();
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002032
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002033 if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
2034 if (!record.mIsForegroundUid) {
2035 interval = Math.max(interval, backgroundThrottleInterval);
Victoria Leaseb711d572012-10-02 13:14:11 -07002036 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002037 if (interval != locationRequest.getInterval()) {
2038 locationRequest = new LocationRequest(locationRequest);
2039 locationRequest.setInterval(interval);
2040 }
2041 }
2042
2043 record.mRequest = locationRequest;
2044 providerRequest.locationRequests.add(locationRequest);
2045 if (!locationRequest.isLowPowerMode()) {
2046 providerRequest.lowPowerMode = false;
2047 }
2048 if (interval < providerRequest.interval) {
2049 providerRequest.reportLocation = true;
2050 providerRequest.interval = interval;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002051 }
2052 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002053
2054 if (providerRequest.reportLocation) {
2055 // calculate who to blame for power
2056 // This is somewhat arbitrary. We pick a threshold interval
2057 // that is slightly higher that the minimum interval, and
2058 // spread the blame across all applications with a request
2059 // under that threshold.
2060 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
2061 for (UpdateRecord record : records) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002062 if (isCurrentProfileLocked(
2063 UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
Victoria Leaseb711d572012-10-02 13:14:11 -07002064 LocationRequest locationRequest = record.mRequest;
Svet Ganove998c732016-06-10 00:12:38 -07002065
2066 // Don't assign battery blame for update records whose
2067 // client has no permission to receive location data.
2068 if (!providerRequest.locationRequests.contains(locationRequest)) {
2069 continue;
2070 }
2071
Victoria Leaseb711d572012-10-02 13:14:11 -07002072 if (locationRequest.getInterval() <= thresholdInterval) {
David Christiee55c9682013-08-22 10:10:34 -07002073 if (record.mReceiver.mWorkSource != null
Narayan Kamath32684dd2018-01-08 17:32:51 +00002074 && isValidWorkSource(record.mReceiver.mWorkSource)) {
David Christie82edc9b2013-07-19 11:31:42 -07002075 worksource.add(record.mReceiver.mWorkSource);
2076 } else {
Narayan Kamath32684dd2018-01-08 17:32:51 +00002077 // Assign blame to caller if there's no WorkSource associated with
2078 // the request or if it's invalid.
David Christie82edc9b2013-07-19 11:31:42 -07002079 worksource.add(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002080 record.mReceiver.mIdentity.mUid,
2081 record.mReceiver.mIdentity.mPackageName);
David Christie82edc9b2013-07-19 11:31:42 -07002082 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002083 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002084 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07002085 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002086 }
2087 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002088
2089 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002090 provider.setRequestLocked(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002091 }
2092
Narayan Kamath32684dd2018-01-08 17:32:51 +00002093 /**
2094 * Whether a given {@code WorkSource} associated with a Location request is valid.
2095 */
2096 private static boolean isValidWorkSource(WorkSource workSource) {
2097 if (workSource.size() > 0) {
2098 // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
2099 // by tags.
2100 return workSource.getName(0) != null;
2101 } else {
2102 // For now, make sure callers have supplied an attribution tag for use with
2103 // AppOpsManager. This might be relaxed in the future.
2104 final ArrayList<WorkChain> workChains = workSource.getWorkChains();
2105 return workChains != null && !workChains.isEmpty() &&
2106 workChains.get(0).getAttributionTag() != null;
2107 }
2108 }
2109
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002110 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002111 public String[] getBackgroundThrottlingWhitelist() {
2112 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002113 return mBackgroundThrottlePackageWhitelist.toArray(new String[0]);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002114 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002115 }
2116
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002117 @GuardedBy("mLock")
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002118 private boolean isThrottlingExemptLocked(Identity identity) {
2119 if (identity.mUid == Process.SYSTEM_UID) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002120 return true;
2121 }
2122
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002123 if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002124 return true;
2125 }
2126
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002127 for (LocationProvider provider : mProviders) {
2128 if (identity.mPackageName.equals(provider.getPackageLocked())) {
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002129 return true;
2130 }
2131 }
2132
Soonil Nagarkar2f1f7e82017-01-24 12:52:10 -08002133 return false;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002134 }
2135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002136 private class UpdateRecord {
2137 final String mProvider;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002138 private final LocationRequest mRealRequest; // original request from client
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002139 LocationRequest mRequest; // possibly throttled version of the request
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002140 private final Receiver mReceiver;
2141 private boolean mIsForegroundUid;
2142 private Location mLastFixBroadcast;
2143 private long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002144
2145 /**
2146 * Note: must be constructed with lock held.
2147 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002148 private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002149 mProvider = provider;
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002150 mRealRequest = request;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002151 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 mReceiver = receiver;
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002153 mIsForegroundUid = isImportanceForeground(
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002154 mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155
2156 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
2157 if (records == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002158 records = new ArrayList<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002159 mRecordsByProvider.put(provider, records);
2160 }
2161 if (!records.contains(this)) {
2162 records.add(this);
2163 }
David Christie2ff96af2014-01-30 16:09:37 -08002164
2165 // Update statistics for historical location requests by package/provider
2166 mRequestStatistics.startRequesting(
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002167 mReceiver.mIdentity.mPackageName, provider, request.getInterval(),
2168 mIsForegroundUid);
2169 }
2170
2171 /**
2172 * Method to be called when record changes foreground/background
2173 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002174 private void updateForeground(boolean isForeground) {
Wyatt Rileyf7075e02018-04-12 17:54:26 -07002175 mIsForegroundUid = isForeground;
2176 mRequestStatistics.updateForeground(
2177 mReceiver.mIdentity.mPackageName, mProvider, isForeground);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002178 }
2179
2180 /**
David Christie2ff96af2014-01-30 16:09:37 -08002181 * Method to be called when a record will no longer be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002182 */
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002183 private void disposeLocked(boolean removeReceiver) {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002184 mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
David Christie2ff96af2014-01-30 16:09:37 -08002185
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002186 // remove from mRecordsByProvider
2187 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
2188 if (globalRecords != null) {
2189 globalRecords.remove(this);
2190 }
2191
2192 if (!removeReceiver) return; // the caller will handle the rest
2193
2194 // remove from Receiver#mUpdateRecords
2195 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002196 receiverRecords.remove(this.mProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002197
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002198 // and also remove the Receiver if it has no more update records
2199 if (receiverRecords.size() == 0) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002200 removeUpdatesLocked(mReceiver);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04002201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 }
2203
2204 @Override
2205 public String toString() {
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002206 return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
gomo48f1a642017-11-10 20:35:46 -08002207 + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground"
2208 : " background")
Wyatt Riley19adc022018-05-22 13:30:51 -07002209 + ")" + " " + mRealRequest + " "
2210 + mReceiver.mWorkSource + "]";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212 }
2213
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002214 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002215 private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
David Christie40e57822013-07-30 11:36:48 -07002216 String packageName, WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002217 IBinder binder = listener.asBinder();
2218 Receiver receiver = mReceivers.get(binder);
2219 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002220 receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
2221 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002222 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002223 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002224 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002225 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002226 return null;
2227 }
Wen Jingcb3ab222014-03-27 13:42:59 +08002228 mReceivers.put(binder, receiver);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002229 }
2230 return receiver;
2231 }
2232
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002233 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002234 private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
David Christie40e57822013-07-30 11:36:48 -07002235 WorkSource workSource, boolean hideFromAppOps) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002236 Receiver receiver = mReceivers.get(intent);
2237 if (receiver == null) {
David Christie40e57822013-07-30 11:36:48 -07002238 receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
2239 hideFromAppOps);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002240 mReceivers.put(intent, receiver);
2241 }
2242 return receiver;
2243 }
2244
Victoria Lease37425c32012-10-16 16:08:48 -07002245 /**
2246 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
2247 * and consistency requirements.
2248 *
2249 * @param request the LocationRequest from which to create a sanitized version
Victoria Lease37425c32012-10-16 16:08:48 -07002250 * @return a version of request that meets the given resolution and consistency requirements
2251 * @hide
2252 */
gomo48f1a642017-11-10 20:35:46 -08002253 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel,
2254 boolean callerHasLocationHardwarePermission) {
Victoria Lease37425c32012-10-16 16:08:48 -07002255 LocationRequest sanitizedRequest = new LocationRequest(request);
gomo48f1a642017-11-10 20:35:46 -08002256 if (!callerHasLocationHardwarePermission) {
2257 // allow setting low power mode only for callers with location hardware permission
2258 sanitizedRequest.setLowPowerMode(false);
2259 }
Victoria Lease37425c32012-10-16 16:08:48 -07002260 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
2261 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07002262 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07002263 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07002264 break;
2265 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07002266 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07002267 break;
2268 }
2269 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07002270 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2271 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002272 }
Victoria Lease37425c32012-10-16 16:08:48 -07002273 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
2274 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07002275 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07002276 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002277 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07002278 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07002279 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002280 }
Victoria Lease37425c32012-10-16 16:08:48 -07002281 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002282 }
2283
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002284 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07002285 if (packageName == null) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002286 throw new SecurityException("invalid package name: " + null);
Nick Pellye0fd6932012-07-11 10:26:13 -07002287 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002288 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07002289 String[] packages = mPackageManager.getPackagesForUid(uid);
2290 if (packages == null) {
2291 throw new SecurityException("invalid UID " + uid);
2292 }
2293 for (String pkg : packages) {
2294 if (packageName.equals(pkg)) return;
2295 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002296 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002297 }
2298
Nick Pellye0fd6932012-07-11 10:26:13 -07002299 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002300 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002301 PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002302 synchronized (mLock) {
2303 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2304 checkPackageName(packageName);
2305 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2306 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2307 request.getProvider());
2308 WorkSource workSource = request.getWorkSource();
2309 if (workSource != null && !workSource.isEmpty()) {
2310 mContext.enforceCallingOrSelfPermission(
2311 Manifest.permission.UPDATE_DEVICE_STATS, null);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002312 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002313 boolean hideFromAppOps = request.getHideFromAppOps();
2314 if (hideFromAppOps) {
2315 mContext.enforceCallingOrSelfPermission(
2316 Manifest.permission.UPDATE_APP_OPS_STATS, null);
2317 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002318 if (request.isLocationSettingsIgnored()) {
2319 mContext.enforceCallingOrSelfPermission(
2320 Manifest.permission.WRITE_SECURE_SETTINGS, null);
2321 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002322 boolean callerHasLocationHardwarePermission =
2323 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2324 == PERMISSION_GRANTED;
2325 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2326 allowedResolutionLevel,
2327 callerHasLocationHardwarePermission);
2328
2329 final int pid = Binder.getCallingPid();
2330 final int uid = Binder.getCallingUid();
2331
2332 long identity = Binder.clearCallingIdentity();
2333 try {
2334
2335 // We don't check for MODE_IGNORED here; we will do that when we go to deliver
2336 // a location.
2337 checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
2338
2339 if (intent == null && listener == null) {
2340 throw new IllegalArgumentException("need either listener or intent");
2341 } else if (intent != null && listener != null) {
2342 throw new IllegalArgumentException(
2343 "cannot register both listener and intent");
2344 }
2345
2346 Receiver receiver;
2347 if (intent != null) {
2348 receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
2349 hideFromAppOps);
2350 } else {
2351 receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
2352 hideFromAppOps);
2353 }
2354 requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
2355 } finally {
2356 Binder.restoreCallingIdentity(identity);
2357 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002358 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002359 }
2360
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002361 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002362 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002363 int uid, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002364 // Figure out the provider. Either its explicitly request (legacy use cases), or
2365 // use the fused provider
2366 if (request == null) request = DEFAULT_LOCATION_REQUEST;
2367 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07002368 if (name == null) {
2369 throw new IllegalArgumentException("provider name must not be null");
2370 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -07002371
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002372 LocationProvider provider = getLocationProviderLocked(name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002373 if (provider == null) {
Victoria Leaseb30f3832013-10-13 12:15:40 -07002374 throw new IllegalArgumentException("provider doesn't exist: " + name);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002375 }
2376
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002377 UpdateRecord record = new UpdateRecord(name, request, receiver);
gomo48f1a642017-11-10 20:35:46 -08002378 if (D) {
2379 Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
2380 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
2381 + (record.mIsForegroundUid ? "foreground" : "background")
2382 + (isThrottlingExemptLocked(receiver.mIdentity)
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002383 ? " [whitelisted]" : "") + ")");
gomo48f1a642017-11-10 20:35:46 -08002384 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002385
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002386 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
2387 if (oldRecord != null) {
2388 oldRecord.disposeLocked(false);
2389 }
2390
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002391 if (!provider.isUseableLocked() && !request.isLocationSettingsIgnored()) {
2392 // Notify the listener that updates are currently disabled - but only if the request
2393 // does not ignore location settings
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002394 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002395 }
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002396
2397 applyRequirementsLocked(name);
2398
David Christie0b837452013-07-29 16:02:13 -07002399 // Update the monitoring here just in case multiple location requests were added to the
2400 // same receiver (this request may be high power and the initial might not have been).
2401 receiver.updateMonitoring(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002402 }
2403
Nick Pellye0fd6932012-07-11 10:26:13 -07002404 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002405 public void removeUpdates(ILocationListener listener, PendingIntent intent,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002406 String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002407 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07002408
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002409 int pid = Binder.getCallingPid();
2410 int uid = Binder.getCallingUid();
2411
2412 if (intent == null && listener == null) {
2413 throw new IllegalArgumentException("need either listener or intent");
2414 } else if (intent != null && listener != null) {
2415 throw new IllegalArgumentException("cannot register both listener and intent");
2416 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002417
Soonil Nagarkar68257742019-01-09 19:42:34 +00002418 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002419 Receiver receiver;
2420 if (intent != null) {
2421 receiver = getReceiverLocked(intent, pid, uid, packageName, null, false);
2422 } else {
2423 receiver = getReceiverLocked(listener, pid, uid, packageName, null, false);
2424 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002425
Soonil Nagarkar68257742019-01-09 19:42:34 +00002426 long identity = Binder.clearCallingIdentity();
2427 try {
2428 removeUpdatesLocked(receiver);
2429 } finally {
2430 Binder.restoreCallingIdentity(identity);
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002431 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002433 }
2434
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002435 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00002436 private void removeUpdatesLocked(Receiver receiver) {
Dianne Hackborn7ff30112012-11-08 11:12:09 -08002437 if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002438
2439 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
2440 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
2441 synchronized (receiver) {
Victoria Lease0aa28602013-05-29 15:28:26 -07002442 receiver.clearPendingBroadcastsLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002444 }
2445
Dianne Hackborn1304f4a2013-07-09 18:17:27 -07002446 receiver.updateMonitoring(false);
2447
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002448 // Record which providers were associated with this listener
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08002449 HashSet<String> providers = new HashSet<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002450 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
2451 if (oldRecords != null) {
2452 // Call dispose() on the obsolete update records.
2453 for (UpdateRecord record : oldRecords.values()) {
David Christie2ff96af2014-01-30 16:09:37 -08002454 // Update statistics for historical location requests by package/provider
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002455 record.disposeLocked(false);
2456 }
2457 // Accumulate providers
2458 providers.addAll(oldRecords.keySet());
2459 }
2460
2461 // update provider
2462 for (String provider : providers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002463 applyRequirementsLocked(provider);
2464 }
2465 }
2466
Nick Pellye0fd6932012-07-11 10:26:13 -07002467 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002468 public Location getLastLocation(LocationRequest r, String packageName) {
2469 if (D) Log.d(TAG, "getLastLocation: " + r);
2470 synchronized (mLock) {
2471 LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
2472 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2473 checkPackageName(packageName);
2474 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2475 request.getProvider());
2476 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07002477
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002478 final int pid = Binder.getCallingPid();
2479 final int uid = Binder.getCallingUid();
2480 final long identity = Binder.clearCallingIdentity();
2481 try {
2482 if (mBlacklist.isBlacklisted(packageName)) {
2483 if (D) {
2484 Log.d(TAG, "not returning last loc for blacklisted app: "
2485 + packageName);
2486 }
2487 return null;
gomo48f1a642017-11-10 20:35:46 -08002488 }
Victoria Leaseb711d572012-10-02 13:14:11 -07002489
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002490 if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel)) {
2491 if (D) {
2492 Log.d(TAG, "not returning last loc for no op app: "
2493 + packageName);
2494 }
2495 return null;
gomo48f1a642017-11-10 20:35:46 -08002496 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002497
Soonil Nagarkar68257742019-01-09 19:42:34 +00002498 // Figure out the provider. Either its explicitly request (deprecated API's),
2499 // or use the fused provider
2500 String name = request.getProvider();
2501 if (name == null) name = LocationManager.FUSED_PROVIDER;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002502 LocationProvider provider = getLocationProviderLocked(name);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002503 if (provider == null) return null;
2504
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002505 // only the current user or location providers may get location this way
2506 if (!isCurrentProfileLocked(UserHandle.getUserId(uid)) && !isLocationProviderLocked(
2507 uid)) {
2508 return null;
2509 }
2510
2511 if (!provider.isUseableLocked()) {
2512 return null;
2513 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002514
2515 Location location;
2516 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2517 // Make sure that an app with coarse permissions can't get frequent location
2518 // updates by calling LocationManager.getLastKnownLocation repeatedly.
2519 location = mLastLocationCoarseInterval.get(name);
2520 } else {
2521 location = mLastLocation.get(name);
2522 }
2523 if (location == null) {
2524 return null;
2525 }
2526
2527 // Don't return stale location to apps with foreground-only location permission.
2528 String op = resolutionLevelToOpStr(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002529 long locationAgeMs = SystemClock.elapsedRealtime()
2530 - location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
2531 if ((locationAgeMs > Settings.Global.getLong(
2532 mContext.getContentResolver(),
2533 Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
2534 DEFAULT_LAST_LOCATION_MAX_AGE_MS))
Soonil Nagarkar68257742019-01-09 19:42:34 +00002535 && (mAppOps.unsafeCheckOp(op, uid, packageName)
2536 == AppOpsManager.MODE_FOREGROUND)) {
2537 return null;
2538 }
2539
2540 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
2541 Location noGPSLocation = location.getExtraLocation(
2542 Location.EXTRA_NO_GPS_LOCATION);
2543 if (noGPSLocation != null) {
2544 return new Location(mLocationFudger.getOrCreate(noGPSLocation));
2545 }
2546 } else {
2547 return new Location(location);
2548 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002549 return null;
2550 } finally {
2551 Binder.restoreCallingIdentity(identity);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002552 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002553 }
2554 }
2555
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002556 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002557 public boolean injectLocation(Location location) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002558 mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
2559 "Location Hardware permission not granted to inject location");
2560 mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
2561 "Access Fine Location permission not granted to inject Location");
2562
2563 if (location == null) {
2564 if (D) {
2565 Log.d(TAG, "injectLocation(): called with null location");
2566 }
2567 return false;
2568 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002569
Soonil Nagarkar68257742019-01-09 19:42:34 +00002570 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002571 LocationProvider provider = getLocationProviderLocked(location.getProvider());
2572 if (provider == null || !provider.isUseableLocked()) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002573 return false;
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002574 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002575
2576 // NOTE: If last location is already available, location is not injected. If
2577 // provider's normal source (like a GPS chipset) have already provided an output
2578 // there is no need to inject this location.
2579 if (mLastLocation.get(provider.getName()) != null) {
2580 return false;
2581 }
2582
2583 updateLastLocationLocked(location, provider.getName());
2584 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002585 }
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08002586 }
2587
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002588 @Override
2589 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
2590 String packageName) {
2591 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07002592 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
2593 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002594 if (intent == null) {
2595 throw new IllegalArgumentException("invalid pending intent: " + null);
Victoria Lease56e675b2012-11-05 19:25:06 -08002596 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002597 checkPackageName(packageName);
2598 synchronized (mLock) {
2599 checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
2600 request.getProvider());
2601 // Require that caller can manage given document
2602 boolean callerHasLocationHardwarePermission =
2603 mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
2604 == PERMISSION_GRANTED;
2605 LocationRequest sanitizedRequest = createSanitizedRequest(request,
2606 allowedResolutionLevel,
2607 callerHasLocationHardwarePermission);
2608
2609 if (D) {
2610 Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
2611 }
2612
2613 // geo-fence manager uses the public location API, need to clear identity
2614 int uid = Binder.getCallingUid();
2615 // TODO: http://b/23822629
2616 if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
2617 // temporary measure until geofences work for secondary users
2618 Log.w(TAG, "proximity alerts are currently available only to the primary user");
2619 return;
2620 }
2621 long identity = Binder.clearCallingIdentity();
2622 try {
2623 mGeofenceManager.addFence(sanitizedRequest, geofence, intent,
2624 allowedResolutionLevel,
2625 uid, packageName);
2626 } finally {
2627 Binder.restoreCallingIdentity(identity);
2628 }
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002629 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002630 }
2631
2632 @Override
2633 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002634 if (intent == null) {
2635 throw new IllegalArgumentException("invalid pending intent: " + null);
2636 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002637 checkPackageName(packageName);
2638
2639 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
2640
Nick Pelly2b7a0d02012-08-17 15:09:44 -07002641 // geo-fence manager uses the public location API, need to clear identity
2642 long identity = Binder.clearCallingIdentity();
2643 try {
2644 mGeofenceManager.removeFence(geofence, intent);
2645 } finally {
2646 Binder.restoreCallingIdentity(identity);
2647 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002648 }
2649
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002650 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002651 public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002652 if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
Takayuki Hoshib254ab6a2014-10-23 16:46:02 +09002653 return false;
2654 }
2655
Anil Admal75b9fd62018-11-28 11:22:50 -08002656 // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
2657 // measurements listeners.
2658 return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 }
2660
Nick Pellye0fd6932012-07-11 10:26:13 -07002661 @Override
Lifu Tang30f95a72016-01-07 23:20:38 -08002662 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002663 mGnssStatusProvider.removeListener(callback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002664 }
2665
Nick Pellye0fd6932012-07-11 10:26:13 -07002666 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002667 public boolean addGnssMeasurementsListener(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002668 IGnssMeasurementsListener listener, String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002669 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
destradaaea8a8a62014-06-23 18:19:03 -07002670 return false;
2671 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002672
Soonil Nagarkar68257742019-01-09 19:42:34 +00002673 synchronized (mLock) {
2674 Identity callerIdentity
2675 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Anil Admal75b9fd62018-11-28 11:22:50 -08002676 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002677 mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002678 long identity = Binder.clearCallingIdentity();
2679 try {
2680 if (isThrottlingExemptLocked(callerIdentity)
2681 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002682 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002683 return mGnssMeasurementsProvider.addListener(listener,
2684 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002685 }
2686 } finally {
2687 Binder.restoreCallingIdentity(identity);
2688 }
2689
2690 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002691 }
destradaaea8a8a62014-06-23 18:19:03 -07002692 }
2693
2694 @Override
gomo226b7b72018-12-12 16:49:39 -08002695 public void injectGnssMeasurementCorrections(
2696 GnssMeasurementCorrections measurementCorrections, String packageName) {
2697 mContext.enforceCallingPermission(
2698 android.Manifest.permission.LOCATION_HARDWARE,
2699 "Location Hardware permission not granted to inject GNSS measurement corrections.");
2700 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2701 mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
2702 } else {
2703 Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
2704 }
2705 }
2706
2707 @Override
2708 public int getGnssCapabilities(String packageName) {
2709 mContext.enforceCallingPermission(
2710 android.Manifest.permission.LOCATION_HARDWARE,
2711 "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
2712 if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
2713 return -1;
2714 }
2715 return mGnssMeasurementsProvider.getGnssCapabilities();
2716 }
2717
2718 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002719 public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002720 if (mGnssMeasurementsProvider == null) {
2721 return;
2722 }
2723
Soonil Nagarkar68257742019-01-09 19:42:34 +00002724 synchronized (mLock) {
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002725 mGnssMeasurementsListeners.remove(listener.asBinder());
2726 mGnssMeasurementsProvider.removeListener(listener);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002727 }
destradaaea8a8a62014-06-23 18:19:03 -07002728 }
2729
2730 @Override
Lifu Tang818aa2c2016-02-01 01:52:00 -08002731 public boolean addGnssNavigationMessageListener(
2732 IGnssNavigationMessageListener listener,
Soonil Nagarkar68257742019-01-09 19:42:34 +00002733 String packageName) {
Wyatt Rileycf879db2017-01-12 13:57:38 -08002734 if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
destradaa4b3e3932014-07-21 18:01:47 -07002735 return false;
2736 }
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002737
Soonil Nagarkar68257742019-01-09 19:42:34 +00002738 synchronized (mLock) {
2739 Identity callerIdentity
2740 = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002741
Anil Admal75b9fd62018-11-28 11:22:50 -08002742 // TODO(b/120481270): Register for client death notification and update map.
Wyatt Riley11cc7492018-01-17 08:48:27 -08002743 mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002744 long identity = Binder.clearCallingIdentity();
2745 try {
2746 if (isThrottlingExemptLocked(callerIdentity)
2747 || isImportanceForeground(
gomo48f1a642017-11-10 20:35:46 -08002748 mActivityManager.getPackageImportance(packageName))) {
Anil Admal75b9fd62018-11-28 11:22:50 -08002749 return mGnssNavigationMessageProvider.addListener(listener,
2750 callerIdentity.mUid, callerIdentity.mPackageName);
Soonil Nagarkar681d7112017-02-23 17:14:16 -08002751 }
2752 } finally {
2753 Binder.restoreCallingIdentity(identity);
2754 }
2755
2756 return true;
Wei Liu5241a4c2015-05-11 14:00:36 -07002757 }
destradaa4b3e3932014-07-21 18:01:47 -07002758 }
2759
2760 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002761 public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
2762 if (mGnssNavigationMessageProvider != null) {
2763 synchronized (mLock) {
2764 mGnssNavigationMessageListeners.remove(listener.asBinder());
2765 mGnssNavigationMessageProvider.removeListener(listener);
2766 }
2767 }
2768 }
2769
2770 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002771 public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
2772 if (providerName == null) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04002773 // throw NullPointerException to remain compatible with previous implementation
2774 throw new NullPointerException();
2775 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002776 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002777 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2778 providerName);
Nick Pellye0fd6932012-07-11 10:26:13 -07002779
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002780 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
2781 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
2782 != PERMISSION_GRANTED)) {
2783 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
2784 }
2785
2786 LocationProvider provider = getLocationProviderLocked(providerName);
2787 if (provider != null) {
2788 provider.sendExtraCommandLocked(command, extras);
2789 }
2790
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002791 return true;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002793 }
2794
Nick Pellye0fd6932012-07-11 10:26:13 -07002795 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002796 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07002797 if (Binder.getCallingUid() != Process.myUid()) {
2798 throw new SecurityException(
2799 "calling sendNiResponse from outside of the system is not allowed");
2800 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04002801 try {
2802 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002803 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002804 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04002805 return false;
2806 }
2807 }
2808
Nick Pellye0fd6932012-07-11 10:26:13 -07002809 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002810 public ProviderProperties getProviderProperties(String providerName) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002811 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002812 checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
2813 providerName);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002814
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002815 LocationProvider provider = getLocationProviderLocked(providerName);
2816 if (provider == null) {
2817 return null;
2818 }
2819 return provider.getPropertiesLocked();
2820 }
Jason Monkb71218a2015-06-17 14:44:39 -04002821 }
2822
Wei Wang980b7c22018-12-06 17:53:00 -08002823 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002824 public String getNetworkProviderPackage() {
Soonil Nagarkar68257742019-01-09 19:42:34 +00002825 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002826 LocationProvider provider = getLocationProviderLocked(NETWORK_PROVIDER);
2827 if (provider == null) {
2828 return null;
2829 }
2830 return provider.getPackageLocked();
Soonil Nagarkar68257742019-01-09 19:42:34 +00002831 }
Maggie2a9409e2018-03-21 11:47:28 -07002832 }
2833
Maggie2a9409e2018-03-21 11:47:28 -07002834 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002835 public void setLocationControllerExtraPackage(String packageName) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002836 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2837 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002838 synchronized (mLock) {
2839 mLocationControllerExtraPackage = packageName;
2840 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002841 }
2842
2843 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002844 public String getLocationControllerExtraPackage() {
2845 synchronized (mLock) {
2846 return mLocationControllerExtraPackage;
2847 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002848 }
2849
2850 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002851 public void setLocationControllerExtraPackageEnabled(boolean enabled) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002852 mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
2853 Manifest.permission.LOCATION_HARDWARE + " permission required");
Soonil Nagarkar68257742019-01-09 19:42:34 +00002854 synchronized (mLock) {
2855 mLocationControllerExtraPackageEnabled = enabled;
2856 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002857 }
2858
2859 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002860 public boolean isLocationControllerExtraPackageEnabled() {
2861 synchronized (mLock) {
2862 return mLocationControllerExtraPackageEnabled
2863 && (mLocationControllerExtraPackage != null);
2864 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002865 }
2866
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002867 private boolean isLocationEnabled() {
2868 return isLocationEnabledForUser(mCurrentUserId);
2869 }
2870
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002871 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002872 public boolean isLocationEnabledForUser(int userId) {
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002873 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002874 if (UserHandle.getCallingUserId() != userId) {
2875 mContext.enforceCallingOrSelfPermission(
2876 Manifest.permission.INTERACT_ACROSS_USERS,
2877 "Requires INTERACT_ACROSS_USERS permission");
2878 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002879
Soonil Nagarkar68257742019-01-09 19:42:34 +00002880 long identity = Binder.clearCallingIdentity();
2881 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002882 boolean enabled;
2883 try {
2884 enabled = Settings.Secure.getIntForUser(
2885 mContext.getContentResolver(),
2886 Settings.Secure.LOCATION_MODE,
2887 userId) != Settings.Secure.LOCATION_MODE_OFF;
2888 } catch (Settings.SettingNotFoundException e) {
2889 // OS upgrade case where mode isn't set yet
2890 enabled = !TextUtils.isEmpty(Settings.Secure.getStringForUser(
Soonil Nagarkar68257742019-01-09 19:42:34 +00002891 mContext.getContentResolver(),
2892 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002893 userId));
2894
2895 try {
2896 Settings.Secure.putIntForUser(
2897 mContext.getContentResolver(),
2898 Settings.Secure.LOCATION_MODE,
2899 enabled
2900 ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
2901 : Settings.Secure.LOCATION_MODE_OFF,
2902 userId);
2903 } catch (RuntimeException ex) {
2904 // any problem with writing should not be propagated
2905 Slog.e(TAG, "error updating location mode", ex);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002906 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00002907 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002908 return enabled;
Soonil Nagarkar68257742019-01-09 19:42:34 +00002909 } finally {
2910 Binder.restoreCallingIdentity(identity);
2911 }
Soonil Nagarkarb2fcddd2019-01-03 15:20:06 -08002912 }
2913
Maggie2a9409e2018-03-21 11:47:28 -07002914 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00002915 public boolean isProviderEnabledForUser(String providerName, int userId) {
Maggie2a9409e2018-03-21 11:47:28 -07002916 // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002917 if (UserHandle.getCallingUserId() != userId) {
2918 mContext.enforceCallingOrSelfPermission(
2919 Manifest.permission.INTERACT_ACROSS_USERS,
2920 "Requires INTERACT_ACROSS_USERS permission");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07002921 }
2922
Maggie2a9409e2018-03-21 11:47:28 -07002923 // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
2924 // so we discourage its use
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002925 if (FUSED_PROVIDER.equals(providerName)) return false;
Maggie2a9409e2018-03-21 11:47:28 -07002926
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002927 synchronized (mLock) {
2928 LocationProvider provider = getLocationProviderLocked(providerName);
2929 return provider != null && provider.isUseableForUserLocked(userId);
Soonil Nagarkar68257742019-01-09 19:42:34 +00002930 }
Maggie2a9409e2018-03-21 11:47:28 -07002931 }
2932
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002933 @GuardedBy("mLock")
2934 private boolean isLocationProviderLocked(int uid) {
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002935 if (uid == Process.SYSTEM_UID) {
2936 return true;
2937 }
Victoria Lease03cdd3d2013-02-01 15:15:54 -08002938
David Christie1f141c12014-05-14 15:11:15 -07002939 String[] packageNames = mPackageManager.getPackagesForUid(uid);
2940 if (packageNames == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002941 return false;
2942 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002943 for (LocationProvider provider : mProviders) {
2944 String packageName = provider.getPackageLocked();
2945 if (packageName == null) {
2946 continue;
2947 }
2948 if (ArrayUtils.contains(packageNames, packageName)) {
David Christie1f141c12014-05-14 15:11:15 -07002949 return true;
2950 }
2951 }
2952 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002953 }
2954
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002955 @GuardedBy("mLock")
2956 private static boolean shouldBroadcastSafeLocked(
Laurent Tu75defb62012-11-01 16:21:52 -07002957 Location loc, Location lastLoc, UpdateRecord record, long now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002958 // Always broadcast the first update
2959 if (lastLoc == null) {
2960 return true;
2961 }
2962
Nick Pellyf1be6862012-05-15 10:53:42 -07002963 // Check whether sufficient time has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002964 long minTime = record.mRealRequest.getFastestInterval();
David Christie1b9b7b12013-04-15 15:31:11 -07002965 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos())
2966 / NANOS_PER_MILLI;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07002967 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002968 return false;
2969 }
2970
2971 // Check whether sufficient distance has been traveled
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002972 double minDistance = record.mRealRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002973 if (minDistance > 0.0) {
2974 if (loc.distanceTo(lastLoc) <= minDistance) {
2975 return false;
2976 }
2977 }
2978
Laurent Tu75defb62012-11-01 16:21:52 -07002979 // Check whether sufficient number of udpates is left
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002980 if (record.mRealRequest.getNumUpdates() <= 0) {
Laurent Tu75defb62012-11-01 16:21:52 -07002981 return false;
2982 }
2983
2984 // Check whether the expiry date has passed
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07002985 return record.mRealRequest.getExpireAt() >= now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002986 }
2987
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08002988 @GuardedBy("mLock")
2989 private void handleLocationChangedLocked(Location location, LocationProvider provider) {
2990 if (!mProviders.contains(provider)) {
2991 return;
2992 }
2993 if (!location.isComplete()) {
2994 Log.w(TAG, "Dropping incomplete location: " + location);
2995 return;
2996 }
2997
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08002998 // only notify passive provider and update last location for locations that come from
2999 // useable providers
3000 if (provider.isUseableLocked()) {
3001 if (!provider.isPassiveLocked()) {
3002 mPassiveProvider.updateLocation(location);
3003 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003004 }
3005
Soonil Nagarkar68257742019-01-09 19:42:34 +00003006 if (D) Log.d(TAG, "incoming location: " + location);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003007 long now = SystemClock.elapsedRealtime();
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003008 if (provider.isUseableLocked()) {
3009 updateLastLocationLocked(location, provider.getName());
Mike Lockwood4e50b782009-04-03 08:24:43 -07003010 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003011
David Christie1b9b7b12013-04-15 15:31:11 -07003012 // Update last known coarse interval location if enough time has passed.
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003013 Location lastLocationCoarseInterval = mLastLocationCoarseInterval.get(
3014 provider.getName());
David Christie1b9b7b12013-04-15 15:31:11 -07003015 if (lastLocationCoarseInterval == null) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003016 lastLocationCoarseInterval = new Location(location);
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003017
3018 if (provider.isUseableLocked()) {
3019 mLastLocationCoarseInterval.put(provider.getName(), lastLocationCoarseInterval);
3020 }
David Christie1b9b7b12013-04-15 15:31:11 -07003021 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003022 long timeDiffNanos = location.getElapsedRealtimeNanos()
David Christie1b9b7b12013-04-15 15:31:11 -07003023 - lastLocationCoarseInterval.getElapsedRealtimeNanos();
3024 if (timeDiffNanos > LocationFudger.FASTEST_INTERVAL_MS * NANOS_PER_MILLI) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003025 lastLocationCoarseInterval.set(location);
David Christie1b9b7b12013-04-15 15:31:11 -07003026 }
3027 // Don't ever return a coarse location that is more recent than the allowed update
3028 // interval (i.e. don't allow an app to keep registering and unregistering for
3029 // location updates to overcome the minimum interval).
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003030 Location noGPSLocation =
David Christie1b9b7b12013-04-15 15:31:11 -07003031 lastLocationCoarseInterval.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3032
Laurent Tu60ec50a2012-10-04 17:00:10 -07003033 // Skip if there are no UpdateRecords for this provider.
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003034 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider.getName());
Laurent Tu60ec50a2012-10-04 17:00:10 -07003035 if (records == null || records.size() == 0) return;
3036
Victoria Lease09016ab2012-09-16 12:33:15 -07003037 // Fetch coarse location
3038 Location coarseLocation = null;
David Christie1b9b7b12013-04-15 15:31:11 -07003039 if (noGPSLocation != null) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003040 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
3041 }
3042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003043 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003044 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07003045
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003046 // Broadcast location to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003047 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003048 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07003049 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07003050
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003051 if (!provider.isUseableLocked() && !r.mRealRequest.isLocationSettingsIgnored()) {
3052 continue;
3053 }
3054
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003055 int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003056 if (!isCurrentProfileLocked(receiverUserId)
3057 && !isLocationProviderLocked(receiver.mIdentity.mUid)) {
Victoria Leaseb711d572012-10-02 13:14:11 -07003058 if (D) {
Victoria Lease269518e2012-10-29 08:25:39 -07003059 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
Victoria Leaseb711d572012-10-02 13:14:11 -07003060 " (current user: " + mCurrentUserId + ", app: " +
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003061 receiver.mIdentity.mPackageName + ")");
Victoria Leaseb711d572012-10-02 13:14:11 -07003062 }
3063 continue;
3064 }
3065
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003066 if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
gomo48f1a642017-11-10 20:35:46 -08003067 if (D) {
3068 Log.d(TAG, "skipping loc update for blacklisted app: " +
3069 receiver.mIdentity.mPackageName);
3070 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07003071 continue;
3072 }
3073
Soonil Nagarkar681d7112017-02-23 17:14:16 -08003074 if (!reportLocationAccessNoThrow(
3075 receiver.mIdentity.mPid,
3076 receiver.mIdentity.mUid,
3077 receiver.mIdentity.mPackageName,
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003078 receiver.mAllowedResolutionLevel)) {
gomo48f1a642017-11-10 20:35:46 -08003079 if (D) {
3080 Log.d(TAG, "skipping loc update for no op app: " +
3081 receiver.mIdentity.mPackageName);
3082 }
Dianne Hackborn5e45ee62013-01-24 19:13:44 -08003083 continue;
3084 }
3085
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003086 Location notifyLocation;
Victoria Lease37425c32012-10-16 16:08:48 -07003087 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
3088 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003089 } else {
Soonil Nagarkarbe93e9c2019-01-08 13:05:03 -08003090 notifyLocation = location; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003091 }
Victoria Lease09016ab2012-09-16 12:33:15 -07003092 if (notifyLocation != null) {
3093 Location lastLoc = r.mLastFixBroadcast;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003094 if ((lastLoc == null)
3095 || shouldBroadcastSafeLocked(notifyLocation, lastLoc, r, now)) {
Victoria Lease09016ab2012-09-16 12:33:15 -07003096 if (lastLoc == null) {
3097 lastLoc = new Location(notifyLocation);
3098 r.mLastFixBroadcast = lastLoc;
3099 } else {
3100 lastLoc.set(notifyLocation);
3101 }
3102 if (!receiver.callLocationChangedLocked(notifyLocation)) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003103 Slog.w(TAG, "RemoteException calling onLocationChanged on "
3104 + receiver);
Victoria Lease09016ab2012-09-16 12:33:15 -07003105 receiverDead = true;
3106 }
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003107 r.mRealRequest.decrementNumUpdates();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003108 }
3109 }
3110
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003111 // TODO: location provider status callbacks have been disabled and deprecated, and are
3112 // guarded behind this setting now. should be removed completely post-Q
3113 if (Settings.Global.getInt(mContext.getContentResolver(),
3114 LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003115 long newStatusUpdateTime = provider.getStatusUpdateTimeLocked();
3116 Bundle extras = new Bundle();
3117 int status = provider.getStatusLocked(extras);
3118
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003119 long prevStatusUpdateTime = r.mLastStatusBroadcast;
3120 if ((newStatusUpdateTime > prevStatusUpdateTime)
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003121 && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003122
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003123 r.mLastStatusBroadcast = newStatusUpdateTime;
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003124 if (!receiver.callStatusChangedLocked(provider.getName(), status, extras)) {
Soonil Nagarkar94749f72018-11-08 11:46:43 -08003125 receiverDead = true;
3126 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
3127 }
Mike Lockwood03ca2162010-04-01 08:10:09 -07003128 }
3129 }
3130
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003131 // track expired records
Soonil Nagarkard4def0c2017-05-23 15:54:55 -07003132 if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003133 if (deadUpdateRecords == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003134 deadUpdateRecords = new ArrayList<>();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003135 }
3136 deadUpdateRecords.add(r);
3137 }
3138 // track dead receivers
3139 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07003140 if (deadReceivers == null) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003141 deadReceivers = new ArrayList<>();
Mike Lockwood03ca2162010-04-01 08:10:09 -07003142 }
3143 if (!deadReceivers.contains(receiver)) {
3144 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003145 }
3146 }
3147 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003148
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003149 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003151 for (Receiver receiver : deadReceivers) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003152 removeUpdatesLocked(receiver);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003153 }
3154 }
3155 if (deadUpdateRecords != null) {
3156 for (UpdateRecord r : deadUpdateRecords) {
3157 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003159 applyRequirementsLocked(provider);
Victoria Lease8b38b292012-12-04 15:04:43 -08003160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003161 }
3162
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003163 @GuardedBy("mLock")
Soonil Nagarkar68257742019-01-09 19:42:34 +00003164 private void updateLastLocationLocked(Location location, String provider) {
Ram Periathiruvadi8671fea2017-12-08 18:35:10 -08003165 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3166 Location lastNoGPSLocation;
3167 Location lastLocation = mLastLocation.get(provider);
3168 if (lastLocation == null) {
3169 lastLocation = new Location(provider);
3170 mLastLocation.put(provider, lastLocation);
3171 } else {
3172 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
3173 if (noGPSLocation == null && lastNoGPSLocation != null) {
3174 // New location has no no-GPS location: adopt last no-GPS location. This is set
3175 // directly into location because we do not want to notify COARSE clients.
3176 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
3177 }
3178 }
3179 lastLocation.set(location);
3180 }
3181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182 // Geocoder
3183
Nick Pellye0fd6932012-07-11 10:26:13 -07003184 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04003185 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07003186 return mGeocodeProvider != null;
3187 }
3188
Nick Pellye0fd6932012-07-11 10:26:13 -07003189 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003191 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003192 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003193 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
3194 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003196 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003197 }
3198
Mike Lockwooda55c3212009-04-15 11:10:11 -04003199
Nick Pellye0fd6932012-07-11 10:26:13 -07003200 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003201 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04003202 double lowerLeftLatitude, double lowerLeftLongitude,
3203 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05003204 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04003205
3206 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05003207 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
3208 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
3209 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04003211 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212 }
3213
3214 // Mock Providers
3215
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003216 private boolean canCallerAccessMockLocation(String opPackageName) {
3217 return mAppOps.noteOp(AppOpsManager.OP_MOCK_LOCATION, Binder.getCallingUid(),
3218 opPackageName) == AppOpsManager.MODE_ALLOWED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003219 }
3220
Nick Pellye0fd6932012-07-11 10:26:13 -07003221 @Override
Soonil Nagarkar68257742019-01-09 19:42:34 +00003222 public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003223 if (!canCallerAccessMockLocation(opPackageName)) {
3224 return;
3225 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003226
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003227 if (PASSIVE_PROVIDER.equals(name)) {
Mike Lockwooda4903f22010-02-17 06:42:23 -05003228 throw new IllegalArgumentException("Cannot mock the passive location provider");
3229 }
3230
Soonil Nagarkar68257742019-01-09 19:42:34 +00003231 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003232 long identity = Binder.clearCallingIdentity();
3233 try {
3234 LocationProvider oldProvider = getLocationProviderLocked(name);
3235 if (oldProvider != null) {
3236 if (oldProvider.isMock()) {
3237 throw new IllegalArgumentException(
3238 "Provider \"" + name + "\" already exists");
3239 }
3240
3241 removeProviderLocked(oldProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003242 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003243
3244 MockLocationProvider mockProviderManager = new MockLocationProvider(name);
3245 addProviderLocked(mockProviderManager);
3246 mockProviderManager.attachLocked(new MockProvider(mockProviderManager, properties));
3247 } finally {
3248 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003249 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003250 }
Ji-Hwan Lee26bdb8f2014-04-21 20:48:19 +09003251 }
3252
Nick Pellye0fd6932012-07-11 10:26:13 -07003253 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003254 public void removeTestProvider(String name, String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003255 if (!canCallerAccessMockLocation(opPackageName)) {
3256 return;
3257 }
3258
Soonil Nagarkar68257742019-01-09 19:42:34 +00003259 synchronized (mLock) {
Soonil Nagarkar68257742019-01-09 19:42:34 +00003260 long identity = Binder.clearCallingIdentity();
3261 try {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003262 LocationProvider testProvider = getLocationProviderLocked(name);
3263 if (testProvider == null || !testProvider.isMock()) {
3264 throw new IllegalArgumentException("Provider \"" + name + "\" unknown");
3265 }
3266
3267 removeProviderLocked(testProvider);
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003268
Soonil Nagarkar68257742019-01-09 19:42:34 +00003269 // reinstate real provider if available
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003270 LocationProvider realProvider = null;
3271 for (LocationProvider provider : mRealProviders) {
3272 if (name.equals(provider.getName())) {
3273 realProvider = provider;
3274 break;
3275 }
3276 }
3277
Soonil Nagarkar68257742019-01-09 19:42:34 +00003278 if (realProvider != null) {
3279 addProviderLocked(realProvider);
3280 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003281 } finally {
3282 Binder.restoreCallingIdentity(identity);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07003283 }
Soonil Nagarkar68257742019-01-09 19:42:34 +00003284 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 }
3286
Nick Pellye0fd6932012-07-11 10:26:13 -07003287 @Override
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003288 public void setTestProviderLocation(String providerName, Location location,
Soonil Nagarkar68257742019-01-09 19:42:34 +00003289 String opPackageName) {
Svet Ganovf7e9cf42015-05-13 10:40:31 -07003290 if (!canCallerAccessMockLocation(opPackageName)) {
3291 return;
3292 }
3293
Soonil Nagarkar68257742019-01-09 19:42:34 +00003294 synchronized (mLock) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003295 LocationProvider testProvider = getLocationProviderLocked(providerName);
3296 if (testProvider == null || !testProvider.isMock()) {
3297 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003298 }
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003299
3300 String locationProvider = location.getProvider();
3301 if (!TextUtils.isEmpty(locationProvider) && !providerName.equals(locationProvider)) {
3302 // The location has an explicit provider that is different from the mock
3303 // provider name. The caller may be trying to fool us via b/33091107.
3304 EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
3305 providerName + "!=" + location.getProvider());
3306 }
3307
3308 ((MockLocationProvider) testProvider).setLocationLocked(location);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003309 }
3310 }
3311
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003312 @Override
3313 public void setTestProviderEnabled(String providerName, boolean enabled, String opPackageName) {
3314 if (!canCallerAccessMockLocation(opPackageName)) {
3315 return;
3316 }
3317
3318 synchronized (mLock) {
3319 LocationProvider testProvider = getLocationProviderLocked(providerName);
3320 if (testProvider == null || !testProvider.isMock()) {
3321 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3322 }
3323
3324 ((MockLocationProvider) testProvider).setEnabledLocked(enabled);
3325 }
3326 }
3327
3328 @Override
3329 public void setTestProviderStatus(String providerName, int status, Bundle extras,
3330 long updateTime, String opPackageName) {
3331 if (!canCallerAccessMockLocation(opPackageName)) {
3332 return;
3333 }
3334
3335 synchronized (mLock) {
3336 LocationProvider testProvider = getLocationProviderLocked(providerName);
3337 if (testProvider == null || !testProvider.isMock()) {
3338 throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown");
3339 }
3340
3341 ((MockLocationProvider) testProvider).setStatusLocked(status, extras, updateTime);
Soonil Nagarkar68257742019-01-09 19:42:34 +00003342 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 }
Nick Pellye0fd6932012-07-11 10:26:13 -07003344
3345 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003346 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003347 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Nick Pellye0fd6932012-07-11 10:26:13 -07003348
Soonil Nagarkar68257742019-01-09 19:42:34 +00003349 synchronized (mLock) {
Siddharth Raybb608c82017-03-16 11:33:34 -07003350 if (args.length > 0 && args[0].equals("--gnssmetrics")) {
3351 if (mGnssMetricsProvider != null) {
3352 pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
3353 }
3354 return;
3355 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003356 pw.println("Current Location Manager state:");
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003357 pw.println(" Location Mode: " + isLocationEnabled());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003358 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003359 for (Receiver receiver : mReceivers.values()) {
3360 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 }
David Christie2ff96af2014-01-30 16:09:37 -08003362 pw.println(" Active Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003363 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
3364 pw.println(" " + entry.getKey() + ":");
3365 for (UpdateRecord record : entry.getValue()) {
3366 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003367 }
3368 }
Wyatt Riley11cc7492018-01-17 08:48:27 -08003369 pw.println(" Active GnssMeasurement Listeners:");
3370 for (Identity identity : mGnssMeasurementsListeners.values()) {
3371 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3372 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3373 }
3374 pw.println(" Active GnssNavigationMessage Listeners:");
3375 for (Identity identity : mGnssNavigationMessageListeners.values()) {
3376 pw.println(" " + identity.mPid + " " + identity.mUid + " "
3377 + identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
3378 }
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003379 pw.println(" Overlay Provider Packages:");
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003380 for (LocationProvider provider : mProviders) {
3381 if (provider.mProvider instanceof LocationProviderProxy) {
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003382 pw.println(" " + provider.getName() + ": "
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003383 + ((LocationProviderProxy) provider.mProvider)
3384 .getConnectedPackageName());
Soonil Nagarkar7decfb62017-01-18 12:18:49 -08003385 }
3386 }
David Christie2ff96af2014-01-30 16:09:37 -08003387 pw.println(" Historical Records by Provider:");
3388 for (Map.Entry<PackageProviderKey, PackageStatistics> entry
3389 : mRequestStatistics.statistics.entrySet()) {
3390 PackageProviderKey key = entry.getKey();
3391 PackageStatistics stats = entry.getValue();
3392 pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
3393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003394 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003395 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
3396 String provider = entry.getKey();
3397 Location location = entry.getValue();
3398 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003399 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003400
David Christie1b9b7b12013-04-15 15:31:11 -07003401 pw.println(" Last Known Locations Coarse Intervals:");
3402 for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
3403 String provider = entry.getKey();
3404 Location location = entry.getValue();
3405 pw.println(" " + provider + ": " + location);
3406 }
3407
Nick Pellye0fd6932012-07-11 10:26:13 -07003408 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003409
Nick Pelly4035f5a2012-08-17 14:43:49 -07003410 pw.append(" ");
3411 mBlacklist.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003412
Wei Wang980b7c22018-12-06 17:53:00 -08003413 if (mLocationControllerExtraPackage != null) {
3414 pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
3415 + " enabled: " + mLocationControllerExtraPackageEnabled);
3416 }
3417
Soonil Nagarkar2b565df2017-02-14 13:33:23 -08003418 if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
3419 pw.println(" Throttling Whitelisted Packages:");
3420 for (String packageName : mBackgroundThrottlePackageWhitelist) {
3421 pw.println(" " + packageName);
3422 }
3423 }
3424
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003425 pw.append(" fudger: ");
gomo48f1a642017-11-10 20:35:46 -08003426 mLocationFudger.dump(fd, pw, args);
Nick Pelly74fa7ea2012-08-13 19:36:38 -07003427
Nick Pelly6fa9ad42012-07-16 12:18:23 -07003428 if (args.length > 0 && "short".equals(args[0])) {
3429 return;
3430 }
Soonil Nagarkar1575a042018-10-24 17:54:54 -07003431 for (LocationProvider provider : mProviders) {
Soonil Nagarkar90da1ab2019-01-04 16:26:59 -08003432 provider.dumpLocked(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06003433 }
Wyatt Rileycf879db2017-01-12 13:57:38 -08003434 if (mGnssBatchingInProgress) {
3435 pw.println(" GNSS batching in progress");
3436 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003437 }
3438 }
3439}